m4/lt~obsolete.m4
src/bin/evas_cserve
src/bin/evas_cserve_tool
+src/bin/evas_cserve2
+src/bin/evas_cserve2_slave
+src/bin/evas_cserve2_client
+src/bin/dummy_slave
*.gcno
*.gcov
src/tests/evas_suite
Rafal Krypa <r.krypa@samsung.com>
Hyoyoung Chang <hyoyoung@gmail.com>
Jérôme Pinot <ngc891@gmail.com>
+Rafael Antognolli <antognolli@profusion.mobi>
* Compute limited bounding box for Smart object.
* Use bounding box to reduce the number of object explored during event propagation.
+
+2012-05-03 Iván Briano (Sachiel)
+
+ * Add CServe2 and image cache2 that makes use of it. Several changes
+ in the buffer and software engines to use the right cache if CServe2
+ is requested for the application.
want_harfbuzz="auto"
want_pixman="no"
want_evas_cserve="yes"
+want_evas_cserve2="yes"
want_evas_engine_buffer="yes"
want_evas_engine_software_xlib="no"
AC_MSG_CHECKING(whether to build shared cache server and support)
AC_MSG_RESULT(${want_evas_cserve})
+# (shm_open (for cache server)
+AC_ARG_ENABLE([evas-cserve2],
+ AC_HELP_STRING([--disable-evas-cserve2],
+ [disable shared cache server 2 support. @<:@default=enabled@:>@]),
+ [
+ if test "x${enableval}" = "xyes" ; then
+ want_evas_cserve2="yes"
+ else
+ want_evas_cserve2="no"
+ fi
+ ])
+AC_MSG_CHECKING(whether to build shared cache server 2 and support)
+AC_MSG_RESULT(${want_evas_cserve2})
+
+if test "x${want_evas_cserve2}" = "xyes"; then
+ want_evas_cserve="no"
+fi
+
shm_open_libs=""
-if test "x${want_evas_cserve}" = "xyes" ; then
+if test "x${want_evas_cserve}" = "xyes" -o "x${want_evas_cserve2}" = "xyes" ; then
EFL_CHECK_SHM_OPEN(
[
- want_evas_cserve="yes"
shm_open_libs=${EFL_SHM_OPEN_LIBS}
],
- [want_evas_cserve="no"])
+ [
+ want_evas_cserve="no"
+ want_evas_cserve2="no"
+ ])
fi
AC_SUBST([shm_open_libs])
AM_CONDITIONAL([EVAS_CSERVE], [test "x${want_evas_cserve}" = "xyes"])
+if test "x${want_evas_cserve2}" = "xyes" ; then
+ AC_DEFINE(EVAS_CSERVE2, 1, [Shared cache server.])
+fi
+
+AM_CONDITIONAL([EVAS_CSERVE2], [test "x${want_evas_cserve2}" = "xyes"])
+
#######################################
doc/Doxyfile
src/Makefile
src/bin/Makefile
+src/bin/loaders/Makefile
+src/bin/loaders/jpeg/Makefile
+src/bin/loaders/png/Makefile
+src/bin/loaders/eet/Makefile
+src/bin/loaders/tiff/Makefile
+src/bin/loaders/xpm/Makefile
+src/bin/loaders/bmp/Makefile
+src/bin/loaders/ico/Makefile
+src/bin/loaders/tga/Makefile
+src/bin/loaders/pmaps/Makefile
+src/bin/loaders/wbmp/Makefile
+src/bin/loaders/psd/Makefile
src/lib/Makefile
src/lib/canvas/Makefile
src/lib/file/Makefile
src/lib/cache/Makefile
+src/lib/cache2/Makefile
src/lib/cserve/Makefile
+src/lib/cserve2/Makefile
src/lib/engines/Makefile
src/lib/engines/common/Makefile
src/lib/engines/common/evas_op_add/Makefile
echo "Features:"
echo " MAGIC_DEBUG.............: $want_evas_magic_debug"
echo " Cache Server............: $want_evas_cserve"
+echo " Cache Server 2..........: $want_evas_cserve2"
echo
dnl
dnl ... DISABLED! some testing has shown that this seems to have some
@EINA_LIBS@
endif
+
+if EVAS_CSERVE2
+
+SUBDIRS = loaders
+
+libexec_PROGRAMS = evas_cserve2 evas_cserve2_slave dummy_slave
+bin_PROGRAMS = evas_cserve2_client
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_LIBEXEC_DIR=\"$(libexecdir)\" \
+@EINA_CFLAGS@
+
+evas_cserve2_SOURCES = \
+evas_cserve2.h \
+evas_cserve2_slave.h \
+evas_cserve2_main.c \
+evas_cserve2_slaves.c \
+evas_cserve2_messages.c \
+evas_cserve2_shm.c \
+evas_cserve2_cache.c \
+evas_cserve2_main_loop_linux.c
+
+evas_cserve2_LDADD = \
+@EINA_LIBS@
+
+evas_cserve2_client_SOURCES = \
+evas_cserve2_client.c
+
+evas_cserve2_slave_SOURCES = \
+evas_cserve2_slave.c \
+evas_cserve2_utils.c
+
+evas_cserve2_slave_LDFLAGS = -export-dynamic
+
+evas_cserve2_slave_LDADD = \
+@EINA_LIBS@
+
+dummy_slave_SOURCES = \
+dummy_slave.c
+
+dummy_slave_LDADD = \
+@EINA_LIBS@
+
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "evas_cserve2.h"
+
+static Eina_Bool
+command_read(int fd, Slave_Command *cmd, void **params)
+{
+ ssize_t ret;
+ int ints[2], size, got = 0;
+ char *buf;
+
+ ret = read(fd, ints, sizeof(int) * 2);
+ if (ret < (int)sizeof(int) * 2)
+ return EINA_FALSE;
+
+ size = ints[0];
+ buf = malloc(size);
+ if (!buf) return EINA_FALSE;
+
+ do {
+ ret = read(fd, buf + got, size - got);
+ if (ret < 0)
+ {
+ /* EINTR means we were interrupted by a signal before anything
+ * was sent, and if we are back here it means that signal was
+ * not meant for us to die. Any other error here is fatal and
+ * should result in the slave terminating.
+ */
+ if (errno == EINTR)
+ continue;
+ free(buf);
+ return EINA_FALSE;
+ }
+ got += ret;
+ } while (got < size);
+
+ *cmd = ints[1];
+ *params = buf;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+response_send(int fd, Slave_Command cmd, void *resp, int size)
+{
+ int sent = 0, ints[2];
+ const char *data = resp;
+ ssize_t ret;
+
+ ints[0] = size;
+ ints[1] = cmd;
+ ret = write(fd, ints, sizeof(int) * 2);
+ if (ret < 0)
+ return EINA_FALSE;
+ if (!size)
+ return EINA_TRUE;
+ do {
+ ret = write(fd, data + sent, size - sent);
+ if (ret < 0)
+ {
+ /* EINTR means we were interrupted by a signal before anything
+ * was sent, and if we are back here it means that signal was
+ * not meant for us to die. Any other error here is fatal and
+ * should result in the slave terminating.
+ */
+ if (errno == EINTR)
+ continue;
+ return EINA_FALSE;
+ }
+ sent += ret;
+ } while (sent < size);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+error_send(int fd, Error_Type err)
+{
+ return response_send(fd, ERROR, &err, sizeof(Error_Type));
+}
+
+void *
+cserve2_shm_map(const char *name, size_t length, off_t offset)
+{
+ void *map;
+ int fd;
+
+ fd = shm_open(name, O_RDWR, 0);
+ if (fd == -1)
+ return MAP_FAILED;
+
+ map = mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, offset);
+
+ close(fd);
+
+ return map;
+}
+
+void
+cserve2_shm_unmap(void *map, size_t length)
+{
+ munmap(map, length);
+}
+
+static Error_Type
+image_open(const char *file __UNUSED__, const char *key __UNUSED__, Slave_Msg_Image_Opened *result)
+{
+ memset(result, 0, sizeof(*result));
+ result->w = 32;
+ result->h = 32;
+ result->frame_count = 1;
+ result->loop_count = 0;
+ result->loop_hint = 0;
+ result->alpha = EINA_TRUE;
+ return CSERVE2_NONE;
+}
+
+static Error_Type
+image_load(const char *shmfile, Slave_Msg_Image_Load *params)
+{
+ char *map = cserve2_shm_map(shmfile, params->shm.mmap_size,
+ params->shm.mmap_offset);
+ if (map == MAP_FAILED)
+ return CSERVE2_RESOURCE_ALLOCATION_FAILED;
+
+ memset(map + params->shm.image_offset, 'A', params->shm.image_size);
+
+ return CSERVE2_NONE;
+}
+
+int main(int c, char **v)
+{
+ int wfd, rfd;
+ Slave_Command cmd;
+ void *params = NULL;;
+ Eina_Bool quit = EINA_FALSE;
+
+ if (c < 3)
+ return 1;
+
+ wfd = atoi(v[1]);
+ rfd = atoi(v[2]);
+
+ while (!quit)
+ {
+ if (!command_read(rfd, &cmd, ¶ms))
+ {
+ error_send(wfd, CSERVE2_INVALID_COMMAND);
+ continue;
+ }
+
+ switch (cmd)
+ {
+ case IMAGE_OPEN:
+ {
+ Slave_Msg_Image_Opened result;
+ Slave_Msg_Image_Open *p;
+ Error_Type err;
+ const char *file, *key;
+ p = params;
+ file = (const char *)(p + sizeof(*p));
+ key = file + strlen(file) + 1;
+ if ((err = image_open(file, key, &result)) != CSERVE2_NONE)
+ error_send(wfd, err);
+ else
+ response_send(wfd, IMAGE_OPEN, &result,
+ sizeof(Slave_Msg_Image_Opened));
+ break;
+ }
+ case IMAGE_LOAD:
+ {
+ Slave_Msg_Image_Load *load_args = params;
+ Error_Type err;
+ const char *shmfile = ((const char *)params) +
+ sizeof(Slave_Msg_Image_Load);
+ if ((err = image_load(shmfile, load_args)) != CSERVE2_NONE)
+ error_send(wfd, err);
+ else
+ response_send(wfd, IMAGE_LOAD, NULL, 0);
+ break;
+ }
+ case SLAVE_QUIT:
+ {
+ quit = EINA_TRUE;
+ break;
+ }
+
+ default:
+ error_send(wfd, CSERVE2_INVALID_COMMAND);
+ }
+ free(params);
+ }
+
+ return 0;
+}
--- /dev/null
+#ifndef _EVAS_CSERVE2_H
+#define _EVAS_CSERVE2_H
+
+#include <Eina.h>
+#include "evas_cs2.h"
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_bin_log_dom, __VA_ARGS__)
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_bin_log_dom, __VA_ARGS__)
+#ifdef WRN
+#undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_bin_log_dom, __VA_ARGS__)
+#ifdef INF
+#undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_bin_log_dom, __VA_ARGS__)
+
+extern int _evas_cserve2_bin_log_dom;
+
+typedef struct _Slave_Proc Slave_Proc;
+typedef struct _Shm_Handle Shm_Handle;
+
+typedef enum {
+ FD_READ = 1,
+ FD_WRITE = 2,
+ FD_ERROR = 4
+} Fd_Flags;
+
+struct _Client {
+ unsigned int id;
+ int socket;
+ struct {
+ Eina_Bool reading;
+ char *buf; // buffer of data being read
+ int done, size;
+ Eina_Binbuf *pending; // pending data to send
+ } msg;
+ struct {
+ Eina_Hash *referencing; // indexed by client file id
+ } files;
+ struct {
+ Eina_Hash *referencing; // indexed by client image id
+ } images;
+};
+
+typedef struct _Client Client;
+
+struct _Image_Load_Opts {
+ unsigned int w, h;
+ unsigned int rx, ry, rw, rh;
+ unsigned int scale_down_by;
+ double dpi;
+ Eina_Bool orientation;
+};
+
+typedef struct _Image_Load_Opts Image_Load_Opts;
+
+typedef enum {
+ IMAGE_OPEN,
+ IMAGE_LOAD,
+ SLAVE_QUIT,
+ ERROR
+} Slave_Command;
+
+struct _Slave_Msg_Image_Open {
+ Eina_Bool has_opts : 1;
+ Eina_Bool has_loader_data : 1;
+};
+
+struct _Slave_Msg_Image_Opened {
+ int w, h;
+ int degree;
+ int scale; /* used by jpeg when loading in smaller sizes */
+ int frame_count;
+ int loop_count;
+ int loop_hint; /* include Evas.h? Copy the enum around? */
+ Eina_Bool alpha : 1;
+ Eina_Bool animated : 1;
+ Eina_Bool rotated : 1;
+
+ Eina_Bool has_loader_data : 1;
+};
+
+struct _Slave_Msg_Image_Load {
+ int w, h;
+ Image_Load_Opts opts;
+ struct {
+ int mmap_offset;
+ int image_offset;
+ int mmap_size;
+ int image_size;
+ } shm;
+ Eina_Bool alpha : 1;
+ Eina_Bool has_loader_data : 1;
+};
+
+struct _Slave_Msg_Image_Loaded {
+ Eina_Bool alpha_sparse : 1;
+};
+
+typedef struct _Slave_Msg_Image_Open Slave_Msg_Image_Open;
+typedef struct _Slave_Msg_Image_Opened Slave_Msg_Image_Opened;
+typedef struct _Slave_Msg_Image_Load Slave_Msg_Image_Load;
+typedef struct _Slave_Msg_Image_Loaded Slave_Msg_Image_Loaded;
+
+typedef void (*Fd_Watch_Cb)(int fd, Fd_Flags flags, void *data);
+typedef void (*Timeout_Cb)(void); /* void* for compat? */
+typedef void (*Main_Loop_Child_Dead_Cb)(int pid, int status); /* void* for compat? */
+typedef void (*Slave_Dead_Cb)(Slave_Proc *slave, void *data);
+typedef void (*Slave_Read_Cb)(Slave_Proc *slave, Slave_Command cmd, void *msg, void *data);
+typedef void (*File_Change_Cb)(const char *path, Eina_Bool deleted, void *data);
+
+void cserve2_client_accept(int fd);
+ssize_t cserve2_client_read(Client *client, void *buf, size_t len);
+ssize_t cserve2_client_write(Client *client, const void *buf, size_t len);
+void cserve2_client_del(Client *client);
+void cserve2_client_deliver(Client *client);
+void cserve2_client_error_send(Client *client, unsigned int rid, int error_code);
+ssize_t cserve2_client_send(Client *client, const void *data, size_t size);
+
+Eina_Bool cserve2_fd_watch_add(int fd, Fd_Flags flags, Fd_Watch_Cb cb, const void *data);
+Eina_Bool cserve2_fd_watch_del(int fd);
+Eina_Bool cserve2_fd_watch_flags_set(int fd, Fd_Flags flags);
+Eina_Bool cserve2_fd_watch_flags_get(int fd, Fd_Flags *flags);
+
+Eina_Bool cserve2_file_change_watch_add(const char *path, File_Change_Cb cb, const void *data);
+Eina_Bool cserve2_file_change_watch_del(const char *path);
+
+void cserve2_on_child_dead_set(Main_Loop_Child_Dead_Cb cb);
+
+void cserve2_timeout_cb_set(int t, Timeout_Cb cb);
+
+Eina_Bool cserve2_main_loop_setup(void);
+void cserve2_main_loop_run(void);
+void cserve2_main_loop_finish(void);
+
+Eina_Bool cserve2_slaves_init(void);
+void cserve2_slaves_shutdown(void);
+int cserve2_slave_available_get(void);
+Eina_Bool cserve2_slave_cmd_dispatch(void *data, Slave_Command cmd, const void *msg, int size);
+Slave_Proc *cserve2_slave_run(const char *exe, Slave_Read_Cb read_cb, Slave_Dead_Cb dead_cb, const void *data);
+void cserve2_slave_send(Slave_Proc *s, Slave_Command cmd, const char *data, size_t size);
+void cserve2_slave_kill(Slave_Proc *s);
+
+void cserve2_message_handler(int fd, Fd_Flags flags, void *data);
+
+Shm_Handle *cserve2_shm_request(size_t size);
+void cserve2_shm_unref(Shm_Handle *shm);
+const char *cserve2_shm_name_get(const Shm_Handle *shm);
+off_t cserve2_shm_map_offset_get(const Shm_Handle *shm);
+off_t cserve2_shm_offset_get(const Shm_Handle *shm);
+size_t cserve2_shm_map_size_get(const Shm_Handle *shm);
+size_t cserve2_shm_size_get(const Shm_Handle *shm);
+
+void cserve2_command_run(Client *client, Message_Type type);
+
+void cserve2_cache_init(void);
+void cserve2_cache_shutdown(void);
+void cserve2_cache_client_new(Client *client);
+void cserve2_cache_client_del(Client *client);
+int cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid);
+void cserve2_cache_file_close(Client *client, unsigned int client_file_id);
+int cserve2_cache_image_opts_set(Client *client, Msg_Setopts *msg);
+void cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid);
+void cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid);
+void cserve2_cache_image_unload(Client *client, unsigned int client_image_id);
+
+void cserve2_cache_requests_process(void);
+
+void cserve2_cache_request_opened(Slave_Msg_Image_Opened *resp, void *data);
+void cserve2_cache_request_loaded(Slave_Msg_Image_Loaded *resp, void *data);
+void cserve2_cache_request_failed(void *data, Error_Type error);
+
+#endif /* _EVAS_CSERVE2_H */
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "evas_cserve2.h"
+
+typedef struct _Request Request;
+typedef struct _Entry Entry;
+typedef struct _Reference Reference;
+typedef struct _Waiter Waiter;
+typedef struct _File_Data File_Data;
+typedef struct _Image_Data Image_Data;
+typedef struct _File_Watch File_Watch;
+
+typedef enum {
+ CSERVE2_IMAGE_FILE,
+ CSERVE2_IMAGE_DATA
+} Entry_Type;
+
+struct _Request {
+ Entry *entry;
+ Eina_List *waiters;
+ Eina_Bool processing;
+};
+
+struct _File_Data {
+ char *path;
+ char *key;
+ int w, h;
+ int frame_count;
+ int loop_count;
+ int loop_hint;
+ const char *loader_data;
+ File_Watch *watcher;
+ Eina_List *images;
+ Eina_Bool alpha : 1;
+ Eina_Bool invalid : 1;
+};
+
+// Default values for load options commented below
+struct _Image_Data {
+ unsigned int file_id;
+ Entry *file;
+ struct {
+ double dpi; // dpi < -1
+ int w, h; // w and h < -1
+ int scale_down; // scale_down < -1
+ int rx, ry, rw, rh; // rx, ry, rw, rh < -1
+ Eina_Bool orientation; // orientation == 0
+ } opts;
+ Shm_Handle *shm;
+ Eina_Bool alpha_sparse : 1;
+ Eina_Bool unused : 1;
+ Eina_Bool doload : 1;
+};
+
+struct _Entry {
+ unsigned int id;
+ Eina_List *references;
+ Request *request;
+ Entry_Type type;
+ union {
+ File_Data file;
+ Image_Data image;
+ };
+};
+
+struct _Reference {
+ Client *client;
+ Entry *entry;
+ unsigned int client_entry_id; // for reverse lookup
+ int count;
+};
+
+struct _Waiter {
+ Reference *ref;
+ unsigned int rid;
+ Message_Type type;
+};
+
+struct _File_Watch {
+ const char *path;
+ Eina_List *entries;
+};
+
+static unsigned int _file_id = 0; // id unique number
+static unsigned int _image_id = 0; // id unique number
+static Eina_Hash *file_ids = NULL; // maps path + key --> file_id
+static Eina_Hash *file_entries = NULL; // maps file_id --> entry
+static Eina_List *open_requests = NULL;
+
+static Eina_Hash *image_ids = NULL; // maps file id + load opts --> image id
+static Eina_Hash *image_entries = NULL; // maps image_id --> entry
+static Eina_List *load_requests = NULL;
+static Eina_List *spload_requests = NULL; // speculative preload requests
+
+static Eina_Hash *file_watch = NULL;
+
+static Eina_List *image_entries_lru = NULL;
+
+static int max_unused_mem_usage = 5 * 1024; /* in kbytes */
+static int unused_mem_usage = 0;
+
+static unsigned int
+_img_opts_id_get(Image_Data *im, char *buf, int size)
+{
+ uintptr_t image_id;
+
+ snprintf(buf, size, "%u:%0.3f:%dx%d:%d:%d,%d+%dx%d:%d",
+ im->file_id, im->opts.dpi, im->opts.w, im->opts.h,
+ im->opts.scale_down, im->opts.rx, im->opts.ry,
+ im->opts.rw, im->opts.rh, im->opts.orientation);
+
+ image_id = (uintptr_t)eina_hash_find(image_ids, buf);
+
+ return image_id;
+}
+
+static int
+_image_entry_size_get(Entry *e)
+{
+ int size = sizeof(Entry);
+ /* XXX: get the overhead of the shm handler too */
+ if (e->image.shm)
+ size += cserve2_shm_size_get(e->image.shm);
+ return size / 1024;
+}
+
+static void
+_file_id_free(Entry *entry)
+{
+ char buf[4096];
+
+ DBG("Removing entry file id: %d, file: \"%s:%s\"",
+ entry->id, entry->file.path, entry->file.key);
+ snprintf(buf, sizeof(buf), "%s:%s", entry->file.path, entry->file.key);
+ eina_hash_del_by_key(file_ids, buf);
+}
+
+static void
+_image_id_free(Entry *entry)
+{
+ char buf[4096];
+
+ DBG("Removing entry image id: %d", entry->id);
+
+ _img_opts_id_get(&entry->image, buf, sizeof(buf));
+ eina_hash_del_by_key(image_ids, buf);
+}
+
+static void
+_image_entry_free(Entry *entry)
+{
+ Entry *fentry = entry->image.file;
+
+ if (entry->request)
+ {
+ if (entry->request->processing)
+ entry->request->entry = NULL;
+ else if (!entry->request->waiters)
+ {
+ if (entry->image.doload)
+ load_requests = eina_list_remove(load_requests, entry->request);
+ else
+ spload_requests = eina_list_remove(spload_requests,
+ entry->request);
+ }
+ }
+
+ if (entry->image.unused)
+ {
+ image_entries_lru = eina_list_remove(image_entries_lru, entry);
+ unused_mem_usage -= _image_entry_size_get(entry);
+ }
+
+ if (fentry)
+ fentry->file.images = eina_list_remove(fentry->file.images, entry);
+ if (entry->image.shm)
+ cserve2_shm_unref(entry->image.shm);
+ free(entry);
+}
+
+static void
+_hash_image_entry_free(void *data)
+{
+ Entry *entry = data;
+
+ _image_id_free(entry);
+ _image_entry_free(entry);
+}
+
+static void
+_file_entry_free(Entry *entry)
+{
+ File_Watch *fw;
+
+ // Should we call free for each of the images too?
+ // If everything goes fine, it's not necessary.
+ if (entry->file.images)
+ {
+ ERR("Freeing file %d (\"%s:%s\") image data still referenced.",
+ entry->id, entry->file.path, entry->file.key);
+ eina_list_free(entry->file.images);
+ }
+
+ if (entry->request)
+ {
+ if (entry->request->processing)
+ entry->request->entry = NULL;
+ else if (!entry->request->waiters)
+ {
+ open_requests = eina_list_remove(open_requests, entry->request);
+ free(entry->request);
+ }
+ }
+
+ if ((fw = entry->file.watcher))
+ {
+ fw->entries = eina_list_remove(fw->entries, entry);
+ if (!fw->entries)
+ eina_hash_del_by_key(file_watch, fw->path);
+ }
+
+ free(entry->file.key);
+ free(entry->file.path);
+ eina_stringshare_del(entry->file.loader_data);
+ free(entry);
+}
+
+static void
+_hash_file_entry_free(void *data)
+{
+ Entry *entry = data;
+ // TODO: Add some checks to make sure that we are freeing an
+ // unused entry.
+
+ _file_id_free(entry);
+ _file_entry_free(entry);
+}
+
+static void
+_file_watch_free(void *data)
+{
+ File_Watch *fw = data;
+ cserve2_file_change_watch_del(fw->path);
+ eina_stringshare_del(fw->path);
+ eina_list_free(fw->entries);
+ free(fw);
+}
+
+void
+cserve2_cache_init(void)
+{
+ file_ids = eina_hash_string_superfast_new(NULL);
+ file_entries = eina_hash_int32_new(_hash_file_entry_free);
+ image_ids = eina_hash_string_superfast_new(NULL);
+ image_entries = eina_hash_string_superfast_new(_hash_image_entry_free);
+ file_watch = eina_hash_string_superfast_new(_file_watch_free);
+}
+
+void
+cserve2_cache_shutdown(void)
+{
+ eina_hash_free(image_entries);
+ eina_hash_free(image_ids);
+ eina_hash_free(file_entries);
+ eina_hash_free(file_ids);
+ eina_hash_free(file_watch);
+}
+
+static void
+_request_answer_del(Eina_List **requests, Request *req, Client *client, Error_Type err)
+{
+ Eina_List *l, *l_next;
+ Waiter *it;
+
+ DBG("Removing answer requests from entry: %d, client: %d",
+ req->entry->id, client->id);
+
+ EINA_LIST_FOREACH_SAFE(req->waiters, l, l_next, it)
+ {
+ if (it->ref->client->id == client->id)
+ {
+ cserve2_client_error_send(client, it->rid, err);
+ req->waiters = eina_list_remove_list(req->waiters, l);
+ free(it);
+ }
+ }
+
+ // FIXME: Should this be really here? I guess that it should be in the
+ // entry_free_cb function, or entry_reference_del, when there are no more
+ // references
+ if (!req->waiters && !req->entry)
+ {
+ *requests = eina_list_remove(*requests, req);
+ free(req);
+ }
+}
+
+static void
+_request_answer_all_del(Eina_List **requests, Request *req, Error_Type err)
+{
+ Waiter *it;
+
+ DBG("Removing all answer requests from entry: %d", req->entry->id);
+
+ EINA_LIST_FREE(req->waiters, it)
+ {
+ cserve2_client_error_send(it->ref->client, it->rid, err);
+ free(it);
+ }
+
+ *requests = eina_list_remove(*requests, req);
+ free(req);
+}
+
+/*
+static void
+_open_request_del(Request *req)
+{
+ Waiter *it;
+
+ EINA_LIST_FREE(req->waiters, it)
+ free(it);
+
+ req->entry->request = NULL;
+
+ open_requests = eina_list_remove(open_requests, req);
+ free(req);
+}
+*/
+
+static void
+_request_answer_add(Request *req, Reference *ref, unsigned int rid, Message_Type type)
+{
+ Waiter *w = malloc(sizeof(*w));
+
+ w->ref = ref;
+ w->rid = rid;
+ w->type = type;
+
+ DBG("Add answer request for entry id: %d, client: %d, rid: %d",
+ req->entry->id, ref->client->id, rid);
+ req->waiters = eina_list_append(req->waiters, w);
+}
+
+static void
+_request_add(Eina_List **requests, Entry *entry, Reference *ref, unsigned int rid, Message_Type type)
+{
+ Request *req;
+
+ // add the request if it doesn't exist yet
+ if (!entry->request)
+ {
+ req = malloc(sizeof(*req));
+ req->entry = entry;
+ req->waiters = NULL;
+ req->processing = EINA_FALSE;
+ entry->request = req;
+ *requests = eina_list_append(*requests, req);
+ DBG("Add request for entry id: %d, client: %d, rid: %d",
+ req->entry->id, ref->client->id, rid);
+ }
+ else
+ req = entry->request;
+
+ if (type != CSERVE2_SETOPTS)
+ _request_answer_add(req, ref, rid, type);
+ else
+ DBG("Adding entry for speculative preload: id=%d", req->entry->id);
+}
+
+static Reference *
+_entry_reference_add(Entry *entry, Client *client, unsigned int client_entry_id)
+{
+ Reference *ref;
+
+ // increase reference for this file
+ ref = malloc(sizeof(*ref));
+ ref->client = client;
+ ref->entry = entry;
+ ref->client_entry_id = client_entry_id;
+ ref->count = 1;
+ entry->references = eina_list_append(entry->references, ref);
+
+ return ref;
+}
+
+static int
+_cserve2_cache_open_requests_process(int nloaders)
+{
+ Request *req;
+ Slave_Msg_Image_Open msg;
+ Entry *entry;
+ char slave_cmd_data[4096];
+ int slave_cmd_size;
+ int path_len, key_len;
+
+ while ((nloaders > 0) && (open_requests))
+ {
+
+ // remove the first element from the list and process this element
+ req = eina_list_data_get(open_requests);
+ open_requests = eina_list_remove_list(open_requests, open_requests);
+
+ entry = req->entry;
+ DBG("Processing OPEN request for file entry: %d", entry->id);
+
+ memset(&msg, 0, sizeof(msg));
+ memcpy(slave_cmd_data, &msg, sizeof(msg));
+
+ path_len = strlen(entry->file.path) + 1;
+ key_len = strlen(entry->file.key) + 1;
+ slave_cmd_size = sizeof(msg) + path_len + key_len;
+ memcpy(slave_cmd_data + sizeof(msg), entry->file.path, path_len);
+ memcpy(slave_cmd_data + sizeof(msg) + path_len, entry->file.key,
+ key_len);
+ cserve2_slave_cmd_dispatch(req, IMAGE_OPEN, slave_cmd_data,
+ slave_cmd_size);
+
+ req->processing = EINA_TRUE;
+ nloaders--;
+ }
+
+ return nloaders;
+}
+
+static void
+_image_preloaded_send(Client *client, unsigned int rid)
+{
+ int size;
+ Msg_Preloaded msg;
+
+ DBG("Sending PRELOADED reply for RID: %d.", rid);
+ memset(&msg, 0, sizeof(msg));
+ msg.base.rid = rid;
+ msg.base.type = CSERVE2_PRELOADED;
+
+ size = sizeof(msg);
+ cserve2_client_send(client, &size, sizeof(size));
+ cserve2_client_send(client, &msg, size);
+}
+
+static void
+_image_loaded_send(Client *client, Entry *entry, unsigned int rid)
+{
+ int size;
+ const char *shmpath = cserve2_shm_name_get(entry->image.shm);
+ Msg_Loaded msg;
+ int path_len;
+ char *buf;
+
+ DBG("Sending LOADED reply for entry %d and RID: %d.", entry->id, rid);
+ path_len = strlen(shmpath) + 1;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.base.rid = rid;
+ msg.base.type = CSERVE2_LOADED;
+
+ msg.shm.mmap_offset = cserve2_shm_map_offset_get(entry->image.shm);
+ msg.shm.use_offset = cserve2_shm_offset_get(entry->image.shm);
+ msg.shm.mmap_size = cserve2_shm_map_size_get(entry->image.shm);
+ msg.shm.image_size = cserve2_shm_size_get(entry->image.shm);
+ msg.alpha_sparse = entry->image.alpha_sparse;
+
+ buf = malloc(sizeof(msg) + path_len);
+
+ memcpy(buf, &msg, sizeof(msg));
+ memcpy(buf + sizeof(msg), shmpath, path_len);
+
+ size = sizeof(msg) + path_len;
+
+ cserve2_client_send(client, &size, sizeof(size));
+ cserve2_client_send(client, buf, size);
+
+ free(buf);
+}
+
+static void
+_cserve2_cache_load_request_run(Request *req)
+{
+ Entry *fentry;
+ Shm_Handle *shm;
+ const char *shmpath, *file, *key, *loader;
+ int shmlen, filelen, keylen, loaderlen;
+ Slave_Msg_Image_Load msg;
+ char *buf, *cur;
+ Entry *ientry;
+ size_t size;
+
+ ientry = req->entry;
+
+ fentry = ientry->image.file;
+ // opening shm for this file
+ shm = cserve2_shm_request(fentry->file.w * fentry->file.h * 4);
+ shmpath = cserve2_shm_name_get(shm);
+ shmlen = strlen(shmpath) + 1;
+
+ file = fentry->file.path;
+ filelen = strlen(file) + 1;
+
+ key = fentry->file.key;
+ keylen = strlen(key) + 1;
+
+ loader = fentry->file.loader_data;
+ if (!loader)
+ loaderlen = 0;
+ else
+ loaderlen = strlen(loader) + 1;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.w = ientry->image.file->file.w;
+ msg.h = ientry->image.file->file.h;
+ msg.alpha = ientry->image.file->file.alpha;
+ msg.opts.w = ientry->image.opts.w;
+ msg.opts.h = ientry->image.opts.h;
+ msg.opts.rx = ientry->image.opts.rx;
+ msg.opts.ry = ientry->image.opts.ry;
+ msg.opts.rw = ientry->image.opts.rw;
+ msg.opts.rh = ientry->image.opts.rh;
+ msg.opts.scale_down_by = ientry->image.opts.scale_down;
+ msg.opts.dpi = ientry->image.opts.dpi;
+ msg.opts.orientation = ientry->image.opts.orientation;
+
+ msg.shm.mmap_offset = cserve2_shm_map_offset_get(shm);
+ msg.shm.image_offset = cserve2_shm_offset_get(shm);
+ msg.shm.mmap_size = cserve2_shm_map_size_get(shm);
+ msg.shm.image_size = cserve2_shm_size_get(shm);
+
+ msg.has_loader_data = !!loaderlen;
+
+ size = sizeof(msg) + shmlen + filelen + keylen + loaderlen;
+
+ buf = calloc(1, size);
+
+ memcpy(buf, &msg, sizeof(msg));
+ cur = buf + sizeof(msg);
+ memcpy(cur, shmpath, shmlen);
+
+ cur += shmlen;
+ memcpy(cur, file, filelen);
+
+ cur += filelen;
+ memcpy(cur, key, keylen);
+
+ cur += keylen;
+ memcpy(cur, loader, loaderlen);
+
+ ientry->image.shm = shm;
+
+ cserve2_slave_cmd_dispatch(req, IMAGE_LOAD, buf, size);
+
+ free(buf);
+}
+
+static int
+_cserve2_cache_load_requests_list_process(Eina_List **queue, int nloaders)
+{
+ Eina_List *skipped = NULL;
+ Request *req;
+
+ while ((nloaders > 0) && (*queue))
+ {
+ // remove the first element from the list and process this element
+ req = eina_list_data_get(*queue);
+ *queue = eina_list_remove_list(*queue, *queue);
+
+ if (!req->entry->image.file)
+ {
+ ERR("File entry doesn't exist for entry id %d", req->entry->id);
+ cserve2_cache_request_failed(req, CSERVE2_INVALID_CACHE);
+ continue;
+ }
+
+ if (req->entry->image.file->request)
+ {
+ /* OPEN still pending, skip this request */
+ skipped = eina_list_append(skipped, req);
+ continue;
+ }
+
+ DBG("Processing LOAD request for image entry: %d", req->entry->id);
+
+ _cserve2_cache_load_request_run(req);
+
+ req->processing = EINA_TRUE;
+
+ nloaders--;
+ }
+
+ EINA_LIST_FREE(skipped, req)
+ *queue = eina_list_append(*queue, req);
+
+ return nloaders;
+}
+
+static void
+_cserve2_cache_load_requests_process(int nloaders)
+{
+ nloaders = _cserve2_cache_load_requests_list_process(&load_requests,
+ nloaders);
+ _cserve2_cache_load_requests_list_process(&spload_requests, nloaders - 1);
+}
+
+
+void
+cserve2_cache_requests_process(void)
+{
+ int avail_loaders;
+
+ avail_loaders = cserve2_slave_available_get();
+ avail_loaders = _cserve2_cache_open_requests_process(avail_loaders);
+ _cserve2_cache_load_requests_process(avail_loaders);
+}
+
+static void
+_entry_unused_push(Entry *e)
+{
+ int size = _image_entry_size_get(e);
+
+ if ((size > max_unused_mem_usage) || !(e->image.doload))
+ {
+ eina_hash_del_by_key(image_entries, &e->id);
+ return;
+ }
+ while (size > (max_unused_mem_usage - unused_mem_usage))
+ {
+ Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru));
+ eina_hash_del_by_key(image_entries, &ie->id);
+ }
+ image_entries_lru = eina_list_append(image_entries_lru, e);
+ e->image.unused = EINA_TRUE;
+ unused_mem_usage += size;
+}
+
+static void
+_entry_reference_del(Entry *entry, Reference *ref)
+{
+ entry->references = eina_list_remove(entry->references, ref);
+
+ if (entry->references)
+ goto free_ref;
+
+ if (entry->type == CSERVE2_IMAGE_FILE)
+ {
+ if (entry->file.invalid)
+ _file_entry_free(entry);
+ else
+ {
+ if (entry->file.images)
+ {
+ Entry *ie;
+ EINA_LIST_FREE(entry->file.images, ie)
+ ie->image.file = NULL;
+ entry->file.images = NULL;
+ }
+ eina_hash_del_by_key(file_entries, &entry->id);
+ }
+ }
+ else if (entry->type == CSERVE2_IMAGE_DATA)
+ {
+ if (!entry->image.file)
+ eina_hash_del_by_key(image_entries, &entry->id);
+ else if (entry->image.file->file.invalid)
+ _image_entry_free(entry);
+ else
+ _entry_unused_push(entry);
+ }
+ else
+ ERR("Wrong type of entry.");
+
+free_ref:
+ free(ref);
+}
+
+static void
+_entry_free_cb(void *data)
+{
+ Reference *ref = data;
+ Entry *entry;
+
+ DBG("Removing client reference for entry id: %d, client: %d",
+ ref->entry->id, ref->client->id);
+
+ entry = ref->entry;
+
+ if (entry->request && !entry->request->processing)
+ {
+ if (entry->type == CSERVE2_IMAGE_FILE)
+ _request_answer_del(&open_requests, entry->request, ref->client,
+ CSERVE2_REQUEST_CANCEL);
+ else
+ {
+ if (entry->image.doload)
+ _request_answer_del(&load_requests, entry->request,
+ ref->client, CSERVE2_REQUEST_CANCEL);
+ else
+ _request_answer_del(&spload_requests, entry->request,
+ ref->client, CSERVE2_REQUEST_CANCEL);
+ }
+ }
+
+ _entry_reference_del(entry, ref);
+}
+
+void
+cserve2_cache_client_new(Client *client)
+{
+ client->files.referencing = eina_hash_int32_new(_entry_free_cb);
+ client->images.referencing = eina_hash_int32_new(_entry_free_cb);
+}
+
+void
+cserve2_cache_client_del(Client *client)
+{
+ // will call _entry_free_cb() for every entry
+ eina_hash_free(client->images.referencing);
+ // will call _entry_free_cb() for every entry
+ eina_hash_free(client->files.referencing);
+}
+
+void
+_image_opened_send(Client *client, Entry *entry, unsigned int rid)
+{
+ int size;
+ Msg_Opened msg;
+
+ DBG("Sending OPENED reply for entry: %d and RID: %d.", entry->id, rid);
+ // clear the struct with possible paddings, since it is not aligned.
+ memset(&msg, 0, sizeof(msg));
+ msg.base.rid = rid;
+ msg.base.type = CSERVE2_OPENED;
+ msg.image.w = entry->file.w;
+ msg.image.h = entry->file.h;
+ msg.image.frame_count = entry->file.frame_count;
+ msg.image.loop_count = entry->file.loop_count;
+ msg.image.loop_hint = entry->file.loop_hint;
+ msg.image.alpha = entry->file.alpha;
+
+ size = sizeof(msg);
+ cserve2_client_send(client, &size, sizeof(size));
+ cserve2_client_send(client, &msg, sizeof(msg));
+ // _cserve2_cache_load_requests_process();
+}
+
+static Entry *
+_image_msg_new(Client *client, Msg_Setopts *msg)
+{
+ Reference *ref;
+ Entry *im_entry;
+
+ ref = eina_hash_find(client->files.referencing, &msg->file_id);
+ if (!ref)
+ {
+ ERR("Couldn't find file id: %d, for image id: %d",
+ msg->file_id, msg->image_id);
+ cserve2_client_error_send(client, msg->base.rid,
+ CSERVE2_INVALID_CACHE);
+ return NULL;
+ }
+ if (ref->entry->file.invalid)
+ {
+ cserve2_client_error_send(client, msg->base.rid,
+ CSERVE2_FILE_CHANGED);
+ return NULL;
+ }
+
+ im_entry = calloc(1, sizeof(*im_entry));
+ im_entry->type = CSERVE2_IMAGE_DATA;
+ im_entry->image.file_id = ref->entry->id;
+ im_entry->image.file = ref->entry;
+ im_entry->image.opts.dpi = msg->opts.dpi;
+ im_entry->image.opts.w = msg->opts.w;
+ im_entry->image.opts.h = msg->opts.h;
+ im_entry->image.opts.scale_down = msg->opts.scale_down;
+ im_entry->image.opts.rx = msg->opts.rx;
+ im_entry->image.opts.ry = msg->opts.ry;
+ im_entry->image.opts.rw = msg->opts.rw;
+ im_entry->image.opts.rh = msg->opts.rh;
+ im_entry->image.opts.orientation = msg->opts.orientation;
+
+ return im_entry;
+}
+
+/*
+static Entry *
+_image_default_new(Entry *file_entry)
+{
+ Entry *im_entry = calloc(1, sizeof(*im_entry));
+ im_entry->image.file_id = file_entry->id;
+ im_entry->image.opts.dpi = -1;
+ im_entry->image.opts.w = -1;
+ im_entry->image.opts.h = -1;
+ im_entry->image.opts.scale_down = -1;
+ im_entry->image.opts.rx = -1;
+ im_entry->image.opts.ry = -1;
+ im_entry->image.opts.rw = -1;
+ im_entry->image.opts.rh = -1;
+ im_entry->image.opts.orientation = 0;
+
+ return im_entry;
+}
+*/
+
+static void
+_file_changed_cb(const char *path __UNUSED__, Eina_Bool deleted __UNUSED__, void *data)
+{
+ File_Watch *fw = data;
+ Entry *e;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(fw->entries, l, e)
+ {
+ Eina_List *ll;
+ Entry *ie;
+
+ e->file.invalid = EINA_TRUE;
+ e->file.watcher = NULL;
+
+ EINA_LIST_FOREACH(e->file.images, ll, ie)
+ {
+ _image_id_free(ie);
+ eina_hash_set(image_entries, &ie->id, NULL);
+ if (ie->request && !ie->request->processing)
+ {
+ if (ie->image.doload)
+ _request_answer_all_del(&load_requests, ie->request,
+ CSERVE2_FILE_CHANGED);
+ else
+ _request_answer_all_del(&spload_requests, ie->request,
+ CSERVE2_FILE_CHANGED);
+ }
+ ie->request = NULL;
+ if (ie->image.unused)
+ _image_entry_free(ie);
+ }
+
+ _file_id_free(e);
+ eina_hash_set(file_entries, &e->id, NULL);
+ if (e->request && !e->request->processing)
+ _request_answer_all_del(&open_requests, ie->request,
+ CSERVE2_FILE_CHANGED);
+ e->request = NULL;
+ if (!e->file.images && !e->references)
+ _file_entry_free(e);
+ }
+
+ eina_hash_del_by_key(file_watch, fw->path);
+}
+
+int
+cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid)
+{
+ uintptr_t file_id;
+ Entry *entry;
+ Reference *ref;
+ File_Watch *fw;
+ char buf[4906];
+
+ // look for this file on client references
+ ref = eina_hash_find(client->files.referencing, &client_file_id);
+ if (ref)
+ {
+ entry = ref->entry;
+
+ if (entry->file.invalid)
+ {
+ cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
+ return -1;
+ }
+
+ DBG("found client file id: %d", client_file_id);
+ ref->count++;
+
+ // File already being loaded, just add the request to be replied
+ if (entry->request)
+ _request_answer_add(entry->request, ref, rid, CSERVE2_OPEN);
+ else
+ _image_opened_send(client, entry, rid);
+ return 0;
+ }
+
+ // search whether the file is already opened by another client
+ snprintf(buf, sizeof(buf), "%s:%s", path, key);
+ file_id = (uintptr_t)eina_hash_find(file_ids, buf);
+ if (file_id)
+ {
+ DBG("found file_id %d for client file id %d",
+ file_id, client_file_id);
+ entry = eina_hash_find(file_entries, &file_id);
+ if (!entry)
+ {
+ ERR("file \"%s\" is in file_ids hash but not in entries hash.",
+ buf);
+ cserve2_client_error_send(client, rid, CSERVE2_INVALID_CACHE);
+ return -1;
+ }
+ ref = _entry_reference_add(entry, client, client_file_id);
+ eina_hash_add(client->files.referencing, &client_file_id, ref);
+ if (entry->request)
+ _request_answer_add(entry->request, ref, rid, CSERVE2_OPEN);
+ else // File already loaded, otherwise there would be a request
+ _image_opened_send(client, entry, rid);
+ return 0;
+ }
+
+ file_id = _file_id++;
+ while ((file_id == 0) || (eina_hash_find(file_entries, &file_id)))
+ file_id = _file_id++;
+
+ DBG("Creating new entry with file_id: %d for file \"%s:%s\"",
+ file_id, path, key);
+ entry = calloc(1, sizeof(*entry));
+ entry->type = CSERVE2_IMAGE_FILE;
+ entry->file.path = strdup(path);
+ entry->file.key = strdup(key);
+ entry->id = file_id;
+ eina_hash_add(file_entries, &file_id, entry);
+ eina_hash_add(file_ids, buf, (void *)file_id);
+ ref = _entry_reference_add(entry, client, client_file_id);
+ eina_hash_add(client->files.referencing, &client_file_id, ref);
+
+ fw = eina_hash_find(file_watch, entry->file.path);
+ if (!fw)
+ {
+ fw = calloc(1, sizeof(File_Watch));
+ fw->path = eina_stringshare_add(entry->file.path);
+ cserve2_file_change_watch_add(fw->path, _file_changed_cb, fw);
+ eina_hash_direct_add(file_watch, fw->path, fw);
+ }
+ fw->entries = eina_list_append(fw->entries, entry);
+ entry->file.watcher = fw;
+
+ _request_add(&open_requests, entry, ref, rid, CSERVE2_OPEN);
+
+ // _open_image_default_set(entry);
+
+ return 0;
+}
+
+void
+cserve2_cache_file_close(Client *client, unsigned int client_file_id)
+{
+ Reference *ref = eina_hash_find(client->files.referencing,
+ &client_file_id);
+ if (!ref)
+ {
+ ERR("Couldn't find file %d in client hash.", client_file_id);
+ return;
+ }
+
+ ref->count--;
+ if (ref->count <= 0)
+ // will call _entry_free_cb() for this entry
+ eina_hash_del_by_key(client->files.referencing, &client_file_id);
+}
+
+int
+cserve2_cache_image_opts_set(Client *client, Msg_Setopts *msg)
+{
+ Entry *entry;
+ Entry *fentry = NULL;
+ Reference *ref, *oldref;
+ unsigned int image_id;
+ char buf[4096];
+
+ oldref = eina_hash_find(client->images.referencing, &msg->image_id);
+
+ // search whether the image is already loaded by another client
+ entry = _image_msg_new(client, msg);
+ if (!entry)
+ return -1;
+ image_id = _img_opts_id_get(&entry->image, buf, sizeof(buf));
+ if (image_id)
+ { // if so, just update the references
+ free(entry);
+ DBG("found image_id %d for client image id %d",
+ image_id, msg->image_id);
+ entry = eina_hash_find(image_entries, &image_id);
+ if (!entry)
+ {
+ ERR("image id %d is in file_ids hash, but not in entries hash"
+ "with entry id %d.", msg->image_id, image_id);
+ cserve2_client_error_send(client, msg->base.rid,
+ CSERVE2_INVALID_CACHE);
+ return -1;
+ }
+
+ if (entry->image.unused)
+ {
+ DBG("Re-using old image entry (id: %d) from the LRU list.",
+ entry->id);
+ entry->image.unused = EINA_FALSE;
+ image_entries_lru = eina_list_remove(image_entries_lru, entry);
+ unused_mem_usage -= _image_entry_size_get(entry);
+ }
+
+ if (oldref && (oldref->entry->id == image_id))
+ return 0;
+
+ ref = _entry_reference_add(entry, client, msg->image_id);
+
+ if (oldref)
+ eina_hash_del_by_key(client->images.referencing, &msg->image_id);
+
+ eina_hash_add(client->images.referencing, &msg->image_id, ref);
+
+ return 0;
+ }
+
+ image_id = _image_id++;
+ while ((image_id == 0) || (eina_hash_find(image_entries, &image_id)))
+ image_id = _image_id++;
+
+ entry->id = image_id;
+ eina_hash_add(image_entries, &image_id, entry);
+ eina_hash_add(image_ids, buf, (void *)image_id);
+ ref = _entry_reference_add(entry, client, msg->image_id);
+
+ if (oldref)
+ eina_hash_del_by_key(client->images.referencing, &msg->image_id);
+ eina_hash_add(client->images.referencing, &msg->image_id, ref);
+
+ fentry = entry->image.file;
+ fentry->file.images = eina_list_append(fentry->file.images, entry);
+
+ _request_add(&spload_requests, entry, ref, msg->base.rid, CSERVE2_SETOPTS);
+ return 0;
+}
+
+void
+cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid)
+{
+ Entry *entry;
+ Reference *ref;
+
+ ref = eina_hash_find(client->images.referencing, &client_image_id);
+ if (!ref)
+ {
+ ERR("Can't load: client %d has no image id %d",
+ client->id, client_image_id);
+ return;
+ }
+ if (ref->entry->image.file->file.invalid)
+ {
+ cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
+ return;
+ }
+
+ DBG("Loading image id: %d", ref->entry->id);
+
+ entry = ref->entry;
+
+ // File already being loaded, just add the request to be replied
+ if (entry->request)
+ {
+ _request_answer_add(entry->request, ref, rid, CSERVE2_LOAD);
+ if ((!entry->request->processing) && (!entry->image.doload))
+ {
+ DBG("Removing entry %d from speculative preload and adding "
+ "to normal load queue.", entry->id);
+ spload_requests = eina_list_remove(spload_requests,
+ entry->request);
+ load_requests = eina_list_append(load_requests, entry->request);
+ }
+ }
+ else if (entry->image.shm)
+ _image_loaded_send(client, entry, rid);
+ else
+ _request_add(&load_requests, entry, ref, rid, CSERVE2_LOAD);
+
+ entry->image.doload = EINA_TRUE;
+}
+
+void
+cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid)
+{
+ Entry *entry;
+ Reference *ref;
+
+ ref = eina_hash_find(client->images.referencing, &client_image_id);
+ if (!ref)
+ {
+ ERR("Can't load: client %d has no image id %d",
+ client->id, client_image_id);
+ return;
+ }
+ if (ref->entry->image.file->file.invalid)
+ {
+ cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
+ return;
+ }
+
+ DBG("Loading image id: %d", ref->entry->id);
+
+ entry = ref->entry;
+
+ // File already being loaded, just add the request to be replied
+ if (entry->request)
+ {
+ _request_answer_add(entry->request, ref, rid, CSERVE2_PRELOAD);
+ if ((!entry->request->processing) && (!entry->image.doload))
+ {
+ DBG("Removing entry %d from speculative preload and adding "
+ "to normal (pre)load queue.", entry->id);
+ spload_requests = eina_list_remove(spload_requests,
+ entry->request);
+ load_requests = eina_list_append(load_requests, entry->request);
+ }
+ }
+ else if (entry->image.shm)
+ _image_preloaded_send(client, rid);
+ else
+ _request_add(&load_requests, entry, ref, rid, CSERVE2_PRELOAD);
+
+ entry->image.doload = EINA_TRUE;
+}
+
+void
+cserve2_cache_image_unload(Client *client, unsigned int client_image_id)
+{
+ Reference *ref = eina_hash_find(client->images.referencing,
+ &client_image_id);
+ if (!ref)
+ {
+ ERR("Couldn't find file %d in client hash.", client_image_id);
+ return;
+ }
+
+ ref->count--;
+ if (ref->count <= 0)
+ // will call _entry_free_cb() for this entry
+ eina_hash_del_by_key(client->images.referencing, &client_image_id);
+}
+
+void
+cserve2_cache_request_opened(Slave_Msg_Image_Opened *resp, void *data)
+{
+ Waiter *w;
+ Request *req = data;
+ Entry *entry;
+
+ entry = req->entry;
+ if (!entry)
+ {
+ Error_Type err = entry->file.invalid
+ ? CSERVE2_FILE_CHANGED
+ : CSERVE2_REQUEST_CANCEL;
+ DBG("File entry for request doesn't exist anymore.");
+ cserve2_cache_request_failed(req, err);
+ entry->request = NULL;
+ return;
+ }
+
+ entry->request = NULL;
+
+ entry->file.w = resp->w;
+ entry->file.h = resp->h;
+ entry->file.frame_count = resp->frame_count;
+ entry->file.loop_count = resp->loop_count;
+ entry->file.loop_hint = resp->loop_hint;
+ entry->file.alpha = resp->alpha;
+ if (resp->has_loader_data)
+ {
+ const char *ldata = (const char *)resp +
+ sizeof(Slave_Msg_Image_Opened);
+ entry->file.loader_data = eina_stringshare_add(ldata);
+ }
+
+ DBG("Finished opening file %d. Notifying %d waiters.", entry->id,
+ req->waiters ? eina_list_count(req->waiters) : 0);
+ EINA_LIST_FREE(req->waiters, w)
+ {
+ _image_opened_send(w->ref->client, entry, w->rid);
+ free(w);
+ }
+
+ free(req);
+}
+
+void
+cserve2_cache_request_loaded(Slave_Msg_Image_Loaded *resp, void *data)
+{
+ Waiter *w;
+ Request *req = data;
+ Entry *entry;
+
+ entry = req->entry;
+ if (!entry)
+ {
+ // FIXME: Wouldn't we keep the entry alive when the file changed
+ // until we send the errors needed and just then delete it? Right now
+ // the check below just makes no sense.
+ // Error_Type err = entry->image.file->file.invalid
+ // ? CSERVE2_FILE_CHANGED
+ // : CSERVE2_REQUEST_CANCEL;
+ DBG("Image entry for request doesn't exist anymore.");
+ cserve2_cache_request_failed(req, CSERVE2_REQUEST_CANCEL);
+ entry->request = NULL;
+ return;
+ }
+
+ entry->request = NULL;
+ entry->image.alpha_sparse = resp->alpha_sparse;
+ if (!entry->image.doload)
+ DBG("Entry %d loaded by speculative preload.", entry->id);
+
+ DBG("Finished loading image %d. Notifying %d waiters.", entry->id,
+ req->waiters ? eina_list_count(req->waiters) : 0);
+ EINA_LIST_FREE(req->waiters, w)
+ {
+ if (w->type == CSERVE2_LOAD)
+ _image_loaded_send(w->ref->client, entry, w->rid);
+ else if (w->type == CSERVE2_PRELOAD)
+ _image_preloaded_send(w->ref->client, w->rid);
+ // else w->type == CSERVE2_SETOPTS --> do nothing
+
+ free(w);
+ }
+
+ free(req);
+}
+
+void
+cserve2_cache_request_failed(void *data, Error_Type type)
+{
+ Waiter *w;
+ Request *req = data;
+ Entry *entry;
+ Eina_List *l;
+ Reference *ref;
+
+ DBG("Request for entry %p failed with error %d", req->entry, type);
+ EINA_LIST_FREE(req->waiters, w)
+ {
+ cserve2_client_error_send(w->ref->client, w->rid, type);
+
+ w->ref->count--;
+ free(w);
+ }
+
+ entry = req->entry;
+ if (!entry)
+ goto free_req;
+
+ EINA_LIST_FOREACH(entry->references, l, ref)
+ {
+ Eina_Hash *hash;
+ if (entry->type == CSERVE2_IMAGE_FILE)
+ hash = ref->client->files.referencing;
+ else if (entry->type == CSERVE2_IMAGE_DATA)
+ hash = ref->client->images.referencing;
+
+ eina_hash_del_by_key(hash, &(ref->client_entry_id));
+ }
+
+free_req:
+ free(req);
+}
--- /dev/null
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "evas_cserve2.h"
+
+static const char *SOCK_PATH = "/tmp/cserve2.socket";
+static unsigned int _rid_count = 0;
+
+static void
+debug_msg(const void *buf, int size)
+{
+ const char *str = buf;
+ int i;
+
+ printf("message: ");
+ for (i = 0; i < size; i++)
+ printf("%x ", str[i]);
+
+ printf("\n");
+}
+
+static int
+_read_line(char *buf, int size)
+{
+ int len;
+ char *c;
+
+ fgets(buf, size, stdin);
+ c = strchr(buf, '#');
+ if (c)
+ *c = '\0';
+ else
+ {
+ c = strchr(buf, '\n');
+ if (c)
+ *c = '\0';
+ }
+ len = strlen(buf);
+
+ return len + 1;
+}
+
+static void *
+parse_input_open(int *size)
+{
+ char path[4096];
+ char key[4096];
+ char line[4096];
+ int path_len, key_len;
+ Msg_Open msg;
+ char *buf;
+ int file_id;
+
+ _read_line(line, sizeof(line));
+ path_len = _read_line(path, sizeof(path));
+ key_len = _read_line(key, sizeof(key));
+
+ sscanf(line, "%d", &file_id);
+
+ buf = malloc(sizeof(msg) + path_len + key_len);
+
+ msg.base.rid = _rid_count++;
+ msg.base.type = CSERVE2_OPEN;
+ msg.file_id = file_id;
+ msg.path_offset = 0;
+ msg.key_offset = path_len;
+
+ memcpy(buf, &msg, sizeof(msg));
+ memcpy(buf + sizeof(msg), path, path_len);
+ memcpy(buf + sizeof(msg) + path_len, key, key_len);
+
+ *size = sizeof(msg) + path_len + key_len;
+
+ return buf;
+}
+
+static void *
+parse_input_setopts(int *size)
+{
+ Msg_Setopts *msg;
+ char line[4096];
+ int file_id, image_id;
+ double dpi;
+ int w, h;
+ int scale;
+ int rx, ry, rw, rh;
+ int orientation;
+
+ // reading file_id, image_id
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d %d", &file_id, &image_id);
+
+ // reading load dpi
+ _read_line(line, sizeof(line));
+ dpi = atof(line);
+
+ // reading load size
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d %d", &w, &h);
+
+ // reading load scale down
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d", &scale);
+
+ // reading load region
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d %d %d %d", &rx, &ry, &rw, &rh);
+
+ // reading orientation
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d", &orientation);
+
+
+ msg = calloc(1, sizeof(*msg));
+
+ msg->base.rid = _rid_count++;
+ msg->base.type = CSERVE2_SETOPTS;
+ msg->file_id = file_id;
+ msg->image_id = image_id;
+ msg->opts.dpi = dpi;
+ msg->opts.w = w;
+ msg->opts.h = h;
+ msg->opts.scale_down = scale;
+ msg->opts.rx = rx;
+ msg->opts.ry = ry;
+ msg->opts.rw = rw;
+ msg->opts.rh = rh;
+ msg->opts.orientation = !!orientation;
+
+ *size = sizeof(*msg);
+
+ return msg;
+}
+
+static void *
+parse_input_load(int *size)
+{
+ Msg_Load *msg;
+ char line[4096];
+ int image_id;
+
+ // read image_id
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d", &image_id);
+
+ msg = calloc(1, sizeof(*msg));
+
+ msg->base.rid = _rid_count++;
+ msg->base.type = CSERVE2_LOAD;
+ msg->image_id = image_id;
+
+ *size = sizeof(*msg);
+
+ return msg;
+}
+
+static void *
+parse_input_preload(int *size)
+{
+ Msg_Preload *msg;
+ char line[4096];
+ int image_id;
+
+ // read image_id
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d", &image_id);
+
+ msg = calloc(1, sizeof(*msg));
+
+ msg->base.rid = _rid_count++;
+ msg->base.type = CSERVE2_PRELOAD;
+ msg->image_id = image_id;
+
+ *size = sizeof(*msg);
+
+ return msg;
+}
+
+static void *
+parse_input_unload(int *size)
+{
+ Msg_Unload *msg;
+ char line[4096];
+ int image_id;
+
+ // read image_id
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d", &image_id);
+
+ msg = calloc(1, sizeof(*msg));
+
+ msg->base.rid = _rid_count++;
+ msg->base.type = CSERVE2_UNLOAD;
+ msg->image_id = image_id;
+
+ *size = sizeof(*msg);
+
+ return msg;
+}
+
+static void *
+parse_input_close(int *size)
+{
+ Msg_Close *msg;
+ char line[4096];
+ int file_id;
+
+ // read file_id
+ _read_line(line, sizeof(line));
+ sscanf(line, "%d", &file_id);
+
+ msg = calloc(1, sizeof(*msg));
+
+ msg->base.rid = _rid_count++;
+ msg->base.type = CSERVE2_CLOSE;
+ msg->file_id = file_id;
+
+ *size = sizeof(*msg);
+
+ return msg;
+}
+
+static void
+parse_answer_opened(const void *buf)
+{
+ const Msg_Opened *msg = buf;
+ printf("OPENED rid = %d\n", msg->base.rid);
+ printf("size: %dx%d, alpha: %d\n\n",
+ msg->image.w, msg->image.h, msg->image.alpha);
+}
+
+static void
+parse_answer_setoptsed(const void *buf)
+{
+ const Msg_Setoptsed *msg = buf;
+ printf("SETOPTSED rid = %d\n", msg->base.rid);
+}
+
+static void
+parse_answer_loaded(const void *buf)
+{
+ const Msg_Loaded *msg = buf;
+ const char *path;
+
+ path = ((const char *)msg) + sizeof(*msg);
+
+ printf("LOADED rid = %d\n", msg->base.rid);
+ printf("shm mmap_offset = 0x%x, use_offset = 0x%x, mmap size = %d bytes\n",
+ msg->shm.mmap_offset, msg->shm.use_offset, msg->shm.mmap_size);
+ printf("shm path: \"%s\"\n\n", path);
+}
+
+static void
+parse_answer_preloaded(const void *buf)
+{
+ const Msg_Preloaded *msg = buf;
+
+ printf("PRELOADED rid = %d\n", msg->base.rid);
+}
+
+static void
+parse_answer_error(const void *buf)
+{
+ const Msg_Error *msg = buf;
+
+ printf("ERROR rid = %d, error = %d\n", msg->base.rid, msg->error);
+}
+
+static void
+parse_answer(const void *buf)
+{
+ const Msg_Base *msg = buf;
+
+ switch (msg->type)
+ {
+ case CSERVE2_OPENED:
+ parse_answer_opened(buf);
+ break;
+ case CSERVE2_SETOPTSED:
+ parse_answer_setoptsed(buf);
+ break;
+ case CSERVE2_LOADED:
+ parse_answer_loaded(buf);
+ break;
+ case CSERVE2_PRELOADED:
+ parse_answer_preloaded(buf);
+ break;
+ case CSERVE2_ERROR:
+ parse_answer_error(buf);
+ break;
+ default:
+ printf("unhandled answer: %d\n", msg->type);
+ }
+}
+
+static struct {
+ const char *name;
+ Message_Type type;
+ void *(*parse_func)(int *size);
+} _msg_types[] = {
+ { "OPEN", CSERVE2_OPEN, parse_input_open },
+ { "OPENED", CSERVE2_OPENED, NULL },
+ { "SETOPTS", CSERVE2_SETOPTS, parse_input_setopts },
+ { "SETOPTSED", CSERVE2_SETOPTSED, NULL },
+ { "LOAD", CSERVE2_LOAD, parse_input_load },
+ { "LOADED", CSERVE2_LOADED, NULL },
+ { "PRELOAD", CSERVE2_PRELOAD, parse_input_preload },
+ { "PRELOADED", CSERVE2_PRELOADED, NULL },
+ { "UNLOAD", CSERVE2_UNLOAD, parse_input_unload },
+ { "CLOSE", CSERVE2_CLOSE, parse_input_close },
+ { NULL, 0, NULL }
+};
+
+int main(void)
+{
+ int s, t, len, skip_cmd = 0;
+ struct sockaddr_un remote;
+ char msgbuf[4096];
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ {
+ perror("socket");
+ exit(1);
+ }
+
+ printf("Trying to connect...\n");
+
+ remote.sun_family = AF_UNIX;
+ strcpy(remote.sun_path, SOCK_PATH);
+ len = strlen(remote.sun_path) + sizeof(remote.sun_family);
+ if (connect(s, (struct sockaddr *)&remote, len) == -1)
+ {
+ perror("connect");
+ exit(1);
+ }
+
+ printf("Connected.\n");
+
+ while(!feof(stdin))
+ {
+ char cmd[1024];
+ int i;
+ int size;
+ void *msg;
+
+ if (skip_cmd)
+ skip_cmd = 0;
+ else
+ printf("\n> ");
+ fgets(cmd, sizeof(cmd), stdin);
+ len = strlen(cmd) - 1;
+ cmd[len] = '\0';
+
+ if (!len)
+ {
+ skip_cmd = 1;
+ continue;
+ }
+
+ for (i = 0; _msg_types[i].name; i++)
+ {
+ if (!strcmp(cmd, _msg_types[i].name))
+ break;
+ }
+
+ // discards the end of the message if we can't parse it
+ if (!_msg_types[i].name)
+ {
+ printf("Invalid command.\n");
+ continue;
+ }
+
+ if (!_msg_types[i].parse_func)
+ {
+ printf("Command %s still unhandled.\n", _msg_types[i].name);
+ continue;
+ }
+
+ msg = _msg_types[i].parse_func(&size);
+
+ if (send(s, &size, sizeof(size), MSG_NOSIGNAL) == -1)
+ {
+ perror("send size");
+ exit(1);
+ }
+ if (send(s, msg, size, MSG_NOSIGNAL) == -1)
+ {
+ perror("send");
+ exit(1);
+ }
+
+ free(msg);
+
+ usleep(100000);
+
+ if ((t=recv(s, &size, sizeof(size), MSG_DONTWAIT)) > 0)
+ {
+ int len = recv(s, msgbuf, size, 0);
+ printf("size of received message: %d\n", len);
+ if (len != size)
+ {
+ printf("couldn't read entire message.\n");
+ continue;
+ }
+ debug_msg(&size, sizeof(size));
+ debug_msg(msgbuf, size);
+ parse_answer(msgbuf);
+ }
+ else
+ {
+ if (t < 0 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
+ continue;
+ else fprintf(stderr, "Server closed connection\n");
+ exit(1);
+ }
+ }
+
+ close(s);
+
+ return 0;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "evas_cserve2.h"
+
+#ifdef CSERVE2_BIN_DEFAULT_COLOR
+#undef CSERVE2_BIN_DEFAULT_COLOR
+#endif
+#define CSERVE2_BIN_DEFAULT_COLOR EINA_COLOR_BLUE
+
+#define MAX_SLAVES 3
+
+struct _Slave_Worker {
+ EINA_INLIST;
+ void *data;
+ Slave_Proc *slave;
+ Eina_Binbuf *ret;
+ int ret_size;
+ Eina_Bool done;
+ Eina_Bool delete_me;
+};
+
+typedef struct _Slave_Worker Slave_Worker;
+
+int _evas_cserve2_bin_log_dom = -1;
+static unsigned int _client_id = 0;
+static Eina_Hash *client_list = NULL;
+static Eina_Inlist *slaves_idle = NULL;
+static Eina_Inlist *slaves_working = NULL;
+
+void
+cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
+{
+ int size;
+ Msg_Error msg;
+
+ // clear the struct with possible paddings, since it is not aligned.
+ memset(&msg, 0, sizeof(msg));
+ msg.base.rid = rid;
+ msg.base.type = CSERVE2_ERROR;
+ msg.error = error_code;
+
+ size = sizeof(msg);
+ cserve2_client_send(client, &size, sizeof(size));
+ cserve2_client_send(client, &msg, sizeof(msg));
+}
+
+static void
+_cserve2_client_image_setoptsed(Client *client, unsigned int rid)
+{
+ int size;
+ Msg_Setoptsed msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.base.rid = rid;
+ msg.base.type = CSERVE2_SETOPTSED;
+
+ size = sizeof(msg);
+ cserve2_client_send(client, &size, sizeof(size));
+ cserve2_client_send(client, &msg, size);
+}
+
+static void
+_slave_dead_cb(Slave_Proc *s __UNUSED__, void *data)
+{
+ Slave_Worker *sw = data;
+
+ if (sw->delete_me)
+ {
+ DBG("Slave killed by cserve2. Restart routine.");
+ free(sw);
+ return;
+ }
+
+ if (!sw->data)
+ {
+ WRN("Slave died with no pending job, but not requested.");
+ slaves_idle = eina_inlist_remove(slaves_idle, EINA_INLIST_GET(sw));
+ free(sw);
+ return;
+ }
+
+ slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));
+ if (!sw->done)
+ cserve2_cache_request_failed(sw->data, CSERVE2_LOADER_DIED);
+ if (sw->ret)
+ eina_binbuf_free(sw->ret);
+ free(sw);
+}
+
+static void
+_slave_read_error(Slave_Worker *sw, void *msg)
+{
+ Error_Type *error = msg;
+
+ cserve2_cache_request_failed(sw->data, *error);
+}
+
+static void
+_slave_read_cb(Slave_Proc *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
+{
+ Slave_Worker *sw = data;
+
+ DBG("Received reply command '%d' from slave '%p'", cmd, sw->slave);
+ switch (cmd)
+ {
+ case IMAGE_OPEN:
+ cserve2_cache_request_opened(msg, sw->data);
+ sw->done = EINA_TRUE;
+ break;
+ case IMAGE_LOAD:
+ cserve2_cache_request_loaded(msg, sw->data);
+ sw->done = EINA_TRUE;
+ break;
+ case ERROR:
+ _slave_read_error(sw, msg);
+ break;
+ default:
+ ERR("Unrecognized command received from slave: %d", cmd);
+ }
+ free(msg);
+
+ // slave finishes its work, put it back to idle list
+ sw->data = NULL;
+ slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));
+
+ if (!sw->delete_me) // if it is being deleted, it shouldn't be in any list
+ slaves_idle = eina_inlist_append(slaves_idle, EINA_INLIST_GET(sw));
+
+ cserve2_cache_requests_process();
+}
+
+int
+cserve2_slave_available_get(void)
+{
+ return MAX_SLAVES - eina_inlist_count(slaves_working);
+}
+
+Eina_Bool
+cserve2_slave_cmd_dispatch(void *data, Slave_Command cmd, const void *msg, int size)
+{
+ Slave_Worker *sw;
+ char *exe;
+
+ DBG("Dispatching command to slave. %d idle slaves, %d working slaves.",
+ eina_inlist_count(slaves_idle), eina_inlist_count(slaves_working));
+
+ // first check if there's an available slave
+ if (slaves_idle)
+ {
+ sw = EINA_INLIST_CONTAINER_GET(slaves_idle, Slave_Worker);
+ slaves_idle = eina_inlist_remove(slaves_idle, slaves_idle);
+ slaves_working = eina_inlist_append(slaves_working,
+ EINA_INLIST_GET(sw));
+
+ sw->data = data;
+ DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
+ cserve2_slave_send(sw->slave, cmd, msg, size);
+ return EINA_TRUE;
+ }
+
+ // no available slave, start a new one
+ sw = calloc(1, sizeof(Slave_Worker));
+ if (!sw) return EINA_FALSE;
+
+ sw->data = data;
+ exe = getenv("EVAS_CSERVE2_SLAVE");
+ if (!exe) exe = "evas_cserve2_slave";
+ sw->slave = cserve2_slave_run(exe, _slave_read_cb, _slave_dead_cb, sw);
+ if (!sw->slave)
+ {
+ ERR("Could not launch slave process");
+ cserve2_cache_request_failed(data, CSERVE2_LOADER_EXEC_ERR);
+ free(sw);
+ return EINA_FALSE;
+ }
+ DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
+ cserve2_slave_send(sw->slave, cmd, msg, size);
+
+ slaves_working = eina_inlist_append(slaves_working, EINA_INLIST_GET(sw));
+
+ return EINA_TRUE;
+}
+
+static void
+_cserve2_client_close(Client *client)
+{
+ Msg_Close *msg = (Msg_Close *)client->msg.buf;
+
+ INF("Received CLOSE command: RID=%d", msg->base.rid);
+ INF("File_ID: %d\n", msg->file_id);
+
+ cserve2_cache_file_close(client, msg->file_id);
+}
+
+static void
+_cserve2_client_unload(Client *client)
+{
+ Msg_Unload *msg = (Msg_Unload *)client->msg.buf;
+
+ INF("Received UNLOAD command: RID=%d", msg->base.rid);
+ INF("Image_ID: %d\n", msg->image_id);
+
+ cserve2_cache_image_unload(client, msg->image_id);
+}
+
+static void
+_cserve2_client_preload(Client *client)
+{
+ Msg_Preload *msg = (Msg_Preload *)client->msg.buf;
+
+ INF("Received PRELOAD command: RID=%d", msg->base.rid);
+ INF("Image_ID: %d\n", msg->image_id);
+
+ cserve2_cache_image_preload(client, msg->image_id, msg->base.rid);
+ cserve2_cache_requests_process();
+}
+
+static void
+_cserve2_client_load(Client *client)
+{
+ Msg_Load *msg = (Msg_Load *)client->msg.buf;
+
+ INF("Received LOAD command: RID=%d", msg->base.rid);
+ INF("Image_ID: %d\n", msg->image_id);
+
+ cserve2_cache_image_load(client, msg->image_id, msg->base.rid);
+ cserve2_cache_requests_process();
+}
+
+static void
+_cserve2_client_setopts(Client *client)
+{
+ Msg_Setopts *msg = (Msg_Setopts *)client->msg.buf;
+
+ INF("Received SETOPTS command: RID=%d", msg->base.rid);
+ INF("File_ID: %d, Image_ID: %d", msg->file_id, msg->image_id);
+ INF("Load Options:");
+ INF("\tdpi: %03.1f", msg->opts.dpi);
+ INF("\tsize: %dx%d", msg->opts.w, msg->opts.h);
+ INF("\tscale down: %d", msg->opts.scale_down);
+ INF("\tregion: %d,%d + %dx%d",
+ msg->opts.rx, msg->opts.ry, msg->opts.rw, msg->opts.rh);
+ INF("\torientation: %d\n", msg->opts.orientation);
+
+ if (cserve2_cache_image_opts_set(client, msg) != 0)
+ return;
+
+ _cserve2_client_image_setoptsed(client, msg->base.rid);
+}
+
+static void
+_cserve2_client_open(Client *client)
+{
+ Msg_Open *msg = (Msg_Open *)client->msg.buf;
+ const char *path, *key;
+
+ path = ((const char *)msg) + sizeof(*msg) + msg->path_offset;
+ key = ((const char *)msg) + sizeof(*msg) + msg->key_offset;
+
+ INF("Received OPEN command: RID=%d", msg->base.rid);
+ INF("File_ID: %d, path=\"%s\", key=\"%s\"\n",
+ msg->file_id, path, key);
+
+ cserve2_cache_file_open(client, msg->file_id, path, key, msg->base.rid);
+ cserve2_cache_requests_process();
+}
+
+void
+cserve2_command_run(Client *client, Message_Type type)
+{
+ switch (type)
+ {
+ case CSERVE2_OPEN:
+ _cserve2_client_open(client);
+ break;
+ case CSERVE2_SETOPTS:
+ _cserve2_client_setopts(client);
+ break;
+ case CSERVE2_LOAD:
+ _cserve2_client_load(client);
+ break;
+ case CSERVE2_PRELOAD:
+ _cserve2_client_preload(client);
+ break;
+ case CSERVE2_UNLOAD:
+ _cserve2_client_unload(client);
+ break;
+ case CSERVE2_CLOSE:
+ _cserve2_client_close(client);
+ break;
+ default:
+ WRN("Unhandled message");
+ }
+}
+
+static void
+_slave_quit_send(Slave_Worker *sw)
+{
+ cserve2_slave_send(sw->slave, SLAVE_QUIT, NULL, 0);
+}
+
+static void
+_slaves_restart(void)
+{
+ Slave_Worker *list, *sw;
+
+ while (slaves_idle) // remove idle workers from idle list
+ {
+ sw = EINA_INLIST_CONTAINER_GET(slaves_idle, Slave_Worker);
+ slaves_idle = eina_inlist_remove(slaves_idle, slaves_idle);
+ sw->delete_me = EINA_TRUE;
+ _slave_quit_send(sw);
+ }
+
+ // working workers will be removed from the working list when they
+ // finish processing their jobs
+ list = EINA_INLIST_CONTAINER_GET(slaves_working, Slave_Worker);
+ EINA_INLIST_FOREACH(list, sw)
+ {
+ sw->delete_me = EINA_TRUE;
+ _slave_quit_send(sw);
+ }
+}
+
+static void
+_timeout_cb(void)
+{
+ static unsigned int slaves_restart = 0;
+
+ slaves_restart++;
+
+ if (slaves_restart == 10)
+ {
+ DBG("kill slaves");
+ _slaves_restart();
+ slaves_restart = 0;
+ }
+
+ cserve2_timeout_cb_set(3000, _timeout_cb);
+}
+
+void
+cserve2_client_accept(int fd)
+{
+ Client *client = calloc(1, sizeof(*client));
+
+ client->socket = fd;
+ client->id = _client_id++;
+
+ while (eina_hash_find(client_list, &client->id))
+ client->id = _client_id++;
+
+ if (!eina_hash_add(client_list, &client->id, client))
+ {
+ Eina_Error err = eina_error_get();
+ ERR("Could not add client to the list: \"%s\"",
+ eina_error_msg_get(err));
+ free(client);
+ close(fd);
+ }
+
+ cserve2_fd_watch_add(fd, FD_READ | FD_ERROR, cserve2_message_handler,
+ client);
+ INF("Client %d connection accepted.", client->id);
+
+ cserve2_cache_client_new(client);
+}
+
+void
+cserve2_client_del(Client *client)
+{
+ eina_hash_del_by_key(client_list, &client->id);
+}
+
+static void
+_client_free(void *data)
+{
+ Client *client = data;
+ cserve2_cache_client_del(client);
+ if (client->msg.pending)
+ eina_binbuf_free(client->msg.pending);
+ cserve2_fd_watch_del(client->socket);
+ close(client->socket);
+ free(data);
+}
+
+static void
+_clients_setup(void)
+{
+ client_list = eina_hash_int32_new(_client_free);
+}
+
+static void
+_clients_finish(void)
+{
+ eina_hash_free(client_list);
+}
+
+int
+main(int argc __UNUSED__, const char *argv[] __UNUSED__)
+{
+ eina_init();
+
+ _evas_cserve2_bin_log_dom = eina_log_domain_register
+ ("evas_cserve2_bin", CSERVE2_BIN_DEFAULT_COLOR);
+ if (_evas_cserve2_bin_log_dom < 0)
+ {
+ EINA_LOG_ERR("impossible to create a log domain.");
+ eina_shutdown();
+ exit(1);
+ }
+
+ if (!cserve2_main_loop_setup())
+ {
+ ERR("could not setup main loop.");
+ goto error;
+ }
+
+ if (!cserve2_slaves_init())
+ {
+ ERR("Could not init slaves subsystem.");
+ goto error;
+ }
+
+ cserve2_cache_init();
+
+ _clients_setup();
+
+ cserve2_timeout_cb_set(3000, _timeout_cb);
+
+ cserve2_main_loop_run();
+
+ _clients_finish();
+
+ cserve2_cache_shutdown();
+
+ _slaves_restart();
+ cserve2_slaves_shutdown();
+
+ cserve2_main_loop_finish();
+
+ eina_log_domain_unregister(_evas_cserve2_bin_log_dom);
+ eina_shutdown();
+ return 0;
+
+error:
+ eina_log_domain_unregister(_evas_cserve2_bin_log_dom);
+ eina_shutdown();
+ exit(1);
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "evas_cserve2.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
+#include <sys/signalfd.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+
+#define MAX_EPOLL_EVENTS 10
+#define MAX_INCOMING_CONN 10
+
+struct _Watch_Data
+{
+ int fd;
+ Fd_Flags flags;
+ Fd_Watch_Cb callback;
+ const void *user_data;
+};
+
+typedef struct _Watch_Data Watch_Data;
+
+struct _Inotify_Data
+{
+ EINA_INLIST;
+ const char *path;
+ int watchid;
+ File_Change_Cb cb;
+ const void *data;
+};
+
+typedef struct _Inotify_Data Inotify_Data;
+
+static int epoll_fd = -1;
+static int signal_fd = -1;
+static int socket_fd = -1;
+static int inotify_fd = -1;
+static struct sockaddr_un socket_local;
+static Eina_Hash *watch_list;
+static Eina_Hash *inotify_path_hash;
+static Eina_Hash *inotify_id_hash;
+static Eina_Bool running;
+static Eina_Bool terminate;
+static int timeout = -1; // in miliseconds
+static long timeout_time = 0; // in miliseconds
+
+static Timeout_Cb timeout_func = NULL;
+static Main_Loop_Child_Dead_Cb reap_children_func = NULL;
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX sizeof(socket_local.sun_path)
+#endif
+
+static void
+_signal_handle_child(struct signalfd_siginfo *sinfo __UNUSED__)
+{
+ int status;
+ pid_t pid;
+
+ while ((pid = waitpid(0, &status, WNOHANG)) > 0)
+ {
+ if (reap_children_func)
+ {
+ reap_children_func(pid, status);
+ continue;
+ }
+
+ DBG("Received SIGCHLD and no handler is set.");
+
+ if (WIFEXITED(status))
+ DBG("Child '%d' exited with status '%d'.", pid,
+ WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ DBG("Child '%d' exited with signal '%d'.", pid,
+ WTERMSIG(status));
+ }
+}
+
+static void
+_signal_handle_int(struct signalfd_siginfo *sinfo __UNUSED__)
+{
+ DBG("Received SIGINT. Honoring request.");
+ terminate = EINA_TRUE;
+}
+
+static void
+_signal_handle_term(struct signalfd_siginfo *sinfo __UNUSED__)
+{
+ DBG("Received SIGTERM. Honoring request.");
+ terminate = EINA_TRUE;
+}
+
+static void
+_signalfd_handler(int fd, Fd_Flags flags __UNUSED__, void *data __UNUSED__)
+{
+ struct signalfd_siginfo sinfo;
+ ssize_t ret;
+
+ for (;;)
+ {
+ ret = read(fd, &sinfo, sizeof(struct signalfd_siginfo));
+ if (ret == -1)
+ {
+ if (errno == EAGAIN)
+ break;
+ ERR("Error reading from signal fd: %m.");
+ return;
+ }
+
+ switch(sinfo.ssi_signo)
+ {
+ case SIGCHLD:
+ _signal_handle_child(&sinfo);
+ break;
+ case SIGINT:
+ _signal_handle_int(&sinfo);
+ break;
+ case SIGTERM:
+ _signal_handle_term(&sinfo);
+ break;
+ default:
+ ERR("Caught unexpected signal '%d'.", sinfo.ssi_signo);
+ }
+ }
+}
+
+static int
+_signalfd_setup(void)
+{
+ sigset_t mask;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ {
+ ERR("Could not set mask of handled signals.");
+ return -1;
+ }
+
+ signal_fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
+ if (signal_fd == -1)
+ ERR("Could not create file descriptor from signalfd.");
+
+ /* ignore SIGPIPE so it's handled by write() and send() as needed */
+ signal(SIGPIPE, SIG_IGN);
+
+ return signal_fd;
+}
+
+static void
+_signalfd_finish(void)
+{
+ sigset_t mask;
+
+ cserve2_fd_watch_del(signal_fd);
+
+ sigemptyset(&mask);
+ sigprocmask(SIG_BLOCK, NULL, &mask);
+
+ close(signal_fd);
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+
+ signal(SIGPIPE, SIG_DFL);
+}
+
+static void
+_socketfd_handler(int fd __UNUSED__, Fd_Flags flags __UNUSED__, void *data __UNUSED__)
+{
+ struct sockaddr_un remote;
+ unsigned int len;
+ int s;
+
+ len = sizeof(struct sockaddr_un);
+ s = accept4(socket_fd, &remote, &len, SOCK_CLOEXEC);
+ if (s == -1)
+ {
+ ERR("Could not accept socket: \"%s\"", strerror(errno));
+ return;
+ }
+
+ cserve2_client_accept(s);
+}
+
+static void
+_socket_path_set(char *path)
+{
+ char *env;
+ char buf[UNIX_PATH_MAX];
+
+ env = getenv("EVAS_CSERVE2_SOCKET");
+ if (env && env[0])
+ {
+ strncpy(path, env, UNIX_PATH_MAX - 1);
+ return;
+ }
+
+ env = getenv("XDG_RUNTIME_DIR");
+ if (!env || !env[0])
+ {
+ env = getenv("HOME");
+ if (!env || !env[0])
+ {
+ env = getenv("TMPDIR");
+ if (!env || !env[0])
+ env = "/tmp";
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "%s/evas-cserve2-%x.socket", env, getuid());
+ /* FIXME: check we can actually create this socket */
+ strcpy(path, buf);
+}
+
+static int
+_socketfd_setup(void)
+{
+ int s;
+ int len;
+
+ s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (s == -1)
+ {
+ ERR("Could not create socketfd: \"%s\"", strerror(errno));
+ return -1;
+ }
+
+ socket_local.sun_family = AF_UNIX;
+ _socket_path_set(socket_local.sun_path);
+ DBG("Using '%s' as server socket.", socket_local.sun_path);
+ unlink(socket_local.sun_path);
+ len = strlen(socket_local.sun_path) + sizeof(socket_local.sun_family);
+ if (bind(s, (struct sockaddr *)&socket_local, len) == -1)
+ {
+ ERR("Could not bind socketfd: \"%s\"", strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ if (listen(s, MAX_INCOMING_CONN) == -1)
+ {
+ ERR("Could not listen on socketfd: \"%s\"", strerror(errno));
+ close(s);
+ unlink(socket_local.sun_path);
+ return -1;
+ }
+
+ socket_fd = s;
+
+ return s;
+}
+
+static void
+_socketfd_finish(void)
+{
+ close(socket_fd);
+ unlink(socket_local.sun_path);
+}
+
+static void
+_inotifyfd_handler(int fd, Fd_Flags flags, void *data __UNUSED__)
+{
+ char buffer[16384];
+ int i = 0;
+ ssize_t size;
+
+ if (flags & FD_ERROR)
+ {
+ ERR("Error on inotify file handler, what to do?");
+ return;
+ }
+
+ size = read(fd, buffer, sizeof(buffer));
+ while (i < size)
+ {
+ struct inotify_event *event;
+ int event_size;
+ Eina_Inlist *ids, *itr;
+ Inotify_Data *id;
+ Eina_Bool deleted;
+
+ event = (struct inotify_event *)&buffer[i];
+ event_size = sizeof(struct inotify_event) + event->len;
+ i += event_size;
+
+ ids = eina_hash_find(inotify_id_hash, &event->wd);
+ if (!ids) continue;
+
+ deleted = !!(event->mask
+ & (IN_DELETE_SELF | IN_MOVE_SELF
+ | IN_IGNORED | IN_UNMOUNT));
+ EINA_INLIST_FOREACH_SAFE(ids, itr, id)
+ id->cb(id->path, deleted, (void *)id->data);
+ }
+}
+
+static void
+_inotify_id_hash_free_cb(void *data)
+{
+ Eina_Inlist *list = data;
+
+ while (list)
+ {
+ Inotify_Data *id;
+ id = EINA_INLIST_CONTAINER_GET(list, Inotify_Data);
+ list = eina_inlist_remove(list, list);
+ eina_stringshare_del(id->path);
+ free(id);
+ }
+}
+
+static int
+_inotifyfd_setup(void)
+{
+ inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ if (inotify_fd == -1)
+ {
+ ERR("Could not create inotifyfd: \"%s\"", strerror(errno));
+ return -1;
+ }
+ inotify_path_hash = eina_hash_string_superfast_new(NULL);
+ inotify_id_hash = eina_hash_int32_new(_inotify_id_hash_free_cb);
+
+ return inotify_fd;
+}
+
+static void
+_inotifyfd_finish(void)
+{
+ close(inotify_fd);
+
+ eina_hash_free(inotify_path_hash);
+ eina_hash_free(inotify_id_hash);
+}
+
+static void
+_watch_data_free_cb(void *data)
+{
+ free(data);
+}
+
+Eina_Bool
+cserve2_main_loop_setup(void)
+{
+ int sfd;
+ int socket;
+ int ifd;
+
+ epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+
+ if (epoll_fd < 0)
+ {
+ ERR("Could not create epoll fd.");
+ return EINA_FALSE;
+ }
+
+ watch_list = eina_hash_int32_new(_watch_data_free_cb);
+ if (!watch_list)
+ {
+ ERR("Could not create watch list hash struct.");
+ close(epoll_fd);
+ return EINA_FALSE;
+ }
+
+ sfd = _signalfd_setup();
+ if (sfd == -1)
+ {
+ ERR("Could not setup signalfd.");
+ close(epoll_fd);
+ eina_hash_free(watch_list);
+ return EINA_FALSE;
+ }
+
+ DBG("Add watch for signal fd: %d", sfd);
+ if (!cserve2_fd_watch_add(sfd, FD_READ, _signalfd_handler, NULL))
+ {
+ ERR("Could not add watch for signalfd.");
+ close(sfd);
+ close(epoll_fd);
+ eina_hash_free(watch_list);
+ return EINA_FALSE;
+ }
+
+ socket = _socketfd_setup();
+ if (socket == -1)
+ {
+ ERR("Could not setup socketfd.");
+ goto error_socket;
+ }
+
+ DBG("Add watch for socket fd: %d", socket);
+ if (!cserve2_fd_watch_add(socket, FD_READ, _socketfd_handler, NULL))
+ {
+ ERR("Could not add watch for socketf.");
+ close(socket);
+ goto error_socket;
+ }
+
+ ifd = _inotifyfd_setup();
+ if (ifd == -1)
+ {
+ ERR("Could not setup inotify.");
+ goto error_inotify;
+ }
+
+ DBG("Add watch for inotify fd: %d", ifd);
+ if (!cserve2_fd_watch_add(ifd, FD_READ, _inotifyfd_handler, NULL))
+ {
+ ERR("Could not add watch for inotifyfd.");
+ close(ifd);
+ goto error_inotify;
+ }
+
+ return EINA_TRUE;
+
+error_inotify:
+ _socketfd_finish();
+
+error_socket:
+ close(sfd);
+ close(epoll_fd);
+ eina_hash_free(watch_list);
+ return EINA_FALSE;
+}
+
+void
+cserve2_main_loop_finish(void)
+{
+ _socketfd_finish();
+
+ _signalfd_finish();
+
+ _inotifyfd_finish();
+
+ eina_hash_free(watch_list);
+
+ close(epoll_fd);
+}
+
+Eina_Bool
+cserve2_fd_watch_add(int fd, Fd_Flags flags, Fd_Watch_Cb cb, const void *data)
+{
+ Watch_Data *w_data;
+ struct epoll_event ev;
+ int err;
+
+ DBG("Add watch for fd %d, flags = 0x%x", fd, flags);
+
+ if ((fd < 0) || (!cb))
+ {
+ ERR("Can't add watch: fd = %d, callback = %p", fd, cb);
+ return EINA_FALSE;
+ }
+
+ w_data = calloc(1, sizeof(*w_data));
+ w_data->fd = fd;
+ w_data->flags = flags;
+ w_data->callback = cb;
+ w_data->user_data = data;
+
+ if (!eina_hash_add(watch_list, &fd, w_data))
+ {
+ ERR("Could not add watch for fd %d to the hash.", fd);
+ free(w_data);
+ return EINA_FALSE;
+ }
+
+ memset(&ev, 0, sizeof(ev));
+ if (flags & FD_READ)
+ ev.events |= EPOLLIN;
+ if (flags & FD_WRITE)
+ ev.events |= EPOLLOUT;
+ ev.data.ptr = w_data;
+
+ err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
+ if (!err < 0)
+ {
+ ERR("Could not create epoll watch for fd %d.", fd);
+ eina_hash_del(watch_list, &fd, NULL);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+cserve2_fd_watch_flags_set(int fd, Fd_Flags flags)
+{
+ Watch_Data *w_data;
+ struct epoll_event ev;
+ int err;
+
+ DBG("Set watch flags for fd %d, flags = 0x%x", fd, flags);
+
+ if (fd < 0)
+ {
+ ERR("Can't modify watch: fd = %d", fd);
+ return EINA_FALSE;
+ }
+
+ w_data = eina_hash_find(watch_list, &fd);
+ if (!w_data)
+ {
+ ERR("Couldn't find data for fd %d: not being watched.", fd);
+ return EINA_FALSE;
+ }
+
+ if (flags == w_data->flags)
+ return EINA_TRUE;
+
+ memset(&ev, 0, sizeof(ev));
+ if (flags & FD_READ)
+ ev.events |= EPOLLIN;
+ if (flags & FD_WRITE)
+ ev.events |= EPOLLOUT;
+ ev.data.ptr = w_data;
+
+ err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev);
+ if (err < 0)
+ {
+ ERR("Could not modify epoll watch for fd: %d", fd);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+cserve2_fd_watch_flags_get(int fd, Fd_Flags *flags)
+{
+ Watch_Data *w_data;
+ if (fd < 0)
+ {
+ ERR("Can't get flags for watch: fd = %d", fd);
+ return EINA_FALSE;
+ }
+
+ w_data = eina_hash_find(watch_list, &fd);
+ if (!w_data)
+ {
+ ERR("Couldn't find data for fd: %d. Is it really being watched?", fd);
+ return EINA_FALSE;
+ }
+
+ *flags = w_data->flags;
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+cserve2_fd_watch_del(int fd)
+{
+ int err;
+
+ DBG("Remove watch for fd %d", fd);
+
+ if (fd < 0)
+ return EINA_FALSE;
+
+ if (!eina_hash_del(watch_list, &fd, NULL))
+ ERR("Could not remove watch for fd %d from watch list hash.", fd);
+
+ err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
+ if (err < 0)
+ {
+ ERR("Could not remove epoll watch for fd %d.", fd);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+cserve2_file_change_watch_add(const char *path, File_Change_Cb cb, const void *data)
+{
+ Inotify_Data *id;
+ Eina_Inlist *ids;
+ unsigned int mask = IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF;
+
+ id = eina_hash_find(inotify_path_hash, path);
+ if (id)
+ {
+ ERR("Attempt to watch changes for path '%s', which is already "
+ "being watched.", path);
+ return EINA_FALSE;
+ }
+
+ id = calloc(1, sizeof(Inotify_Data));
+ if (!id)
+ {
+ ERR("Could not alloc Inotify_Data instance.");
+ return EINA_FALSE;
+ }
+
+ id->watchid = inotify_add_watch(inotify_fd, path, mask);
+ if (id->watchid == -1)
+ {
+ ERR("Could not add inotify watch for %s: %m.", path);
+ free(id);
+ return EINA_FALSE;
+ }
+
+ id->path = eina_stringshare_add(path);
+ id->cb = cb;
+ id->data = data;
+
+ eina_hash_direct_add(inotify_path_hash, id->path, id);
+
+ ids = eina_hash_find(inotify_id_hash, &id->watchid);
+ ids = eina_inlist_append(ids, EINA_INLIST_GET(id));
+ eina_hash_set(inotify_id_hash, &id->watchid, ids);
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+cserve2_file_change_watch_del(const char *path)
+{
+ Inotify_Data *id;
+ Eina_Inlist *ids;
+ int wd;
+
+ id = eina_hash_set(inotify_path_hash, path, NULL);
+ if (!id)
+ {
+ ERR("Requested to remove change watch for %s, but it's not being "
+ "watched.", path);
+ return EINA_FALSE;
+ }
+
+ ids = eina_hash_find(inotify_id_hash, &id->watchid);
+ ids = eina_inlist_remove(ids, EINA_INLIST_GET(id));
+ eina_hash_set(inotify_id_hash, &id->watchid, ids);
+
+ wd = id->watchid;
+ eina_stringshare_del(id->path);
+ free(id);
+
+ if (!ids)
+ {
+ if (inotify_rm_watch(inotify_fd, wd) == -1)
+ {
+ ERR("Could not remove change watch for %s: %m", path);
+ return EINA_FALSE;
+ }
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_update_timeout(void)
+{
+ struct timeval timev;
+ long cur_time;
+
+ if (timeout <= 0)
+ return;
+
+ gettimeofday(&timev, NULL);
+ cur_time = timev.tv_sec * 1000 + timev.tv_usec / 1000;
+ timeout -= cur_time - timeout_time;
+ timeout_time = cur_time;
+
+ if (timeout < 0)
+ timeout = 0;
+}
+
+void
+cserve2_timeout_cb_set(int t, Timeout_Cb cb)
+{
+ struct timeval timev;
+ if (cb && t <= 0)
+ {
+ ERR("timeout must be a value greater than 0 to set a callback."
+ " given timeout: %d miliseconds", t);
+ return;
+ }
+
+ if (!cb)
+ {
+ DBG("Removing timeout callback.");
+ timeout = -1;
+ cb = NULL;
+ return;
+ }
+
+ //DBG("Setting timeout to: %d miliseconds", t);
+ gettimeofday(&timev, NULL);
+ timeout_time = timev.tv_sec * 1000 + timev.tv_usec / 1000;
+ timeout = t;
+ timeout_func = cb;
+}
+
+void
+cserve2_on_child_dead_set(Main_Loop_Child_Dead_Cb cb)
+{
+ reap_children_func = cb;
+}
+
+void
+cserve2_main_loop_run(void)
+{
+ running = EINA_TRUE;
+ terminate = EINA_FALSE;
+
+ for (;;)
+ {
+ struct epoll_event events[MAX_EPOLL_EVENTS];
+ int n, nfds;
+
+ if (terminate)
+ break;
+
+ nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, timeout);
+ if (nfds < 0)
+ {
+ ERR("An error occurred when reading the epoll fd.");
+ ERR("%s", strerror(errno));
+ break;
+ }
+ if (nfds == 0) // timeout occurred
+ {
+ timeout = -1;
+ if (!timeout_func)
+ ERR("Timeout expired, but no timeout function set.");
+ else
+ timeout_func();
+ }
+
+ for (n = 0; n < nfds; n++)
+ {
+ Watch_Data *data = events[n].data.ptr;
+ Fd_Flags flags = 0;
+
+ if (!data)
+ continue;
+
+ if (!data->callback)
+ continue;
+
+ if (events[n].events & EPOLLIN)
+ flags |= FD_READ;
+ if (events[n].events & EPOLLOUT)
+ flags |= FD_WRITE;
+ if (events[n].events & EPOLLERR)
+ flags |= FD_ERROR;
+ data->callback(data->fd, flags, (void *)data->user_data);
+ }
+
+ _update_timeout();
+ }
+
+ running = EINA_FALSE;
+}
+
+ssize_t
+cserve2_client_read(Client *client, void *buf, size_t len)
+{
+ return recv(client->socket, buf, len, MSG_DONTWAIT);
+}
+
+ssize_t
+cserve2_client_write(Client *client, const void *data, size_t size)
+{
+ return send(client->socket, data, size, MSG_NOSIGNAL | MSG_DONTWAIT);
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include "evas_cserve2.h"
+
+// #define DEBUG_MSG 1
+
+static void
+debug_msg(const char *typestr, const void *buf, int size)
+{
+#ifdef DEBUG_MSG
+ const char *str = buf;
+ int i;
+
+ printf("message %s: ", typestr);
+ for (i = 0; i < size; i++)
+ printf("%x ", str[i]);
+
+ printf("\n");
+#endif
+}
+
+static void
+_client_msg_allocate_buf(Client *client, int msgsize)
+{
+ client->msg.reading = EINA_TRUE;
+ client->msg.buf = malloc(msgsize + 1);
+ client->msg.size = msgsize;
+ client->msg.done = 0;
+}
+
+static void
+_client_msg_free(Client *client)
+{
+ client->msg.reading = EINA_FALSE;
+ free(client->msg.buf);
+}
+
+static void
+_client_msg_parse(Client *client)
+{
+ Msg_Base *msg = (Msg_Base *)client->msg.buf;
+ DBG("Message received. Size: %d; type = %d",
+ client->msg.size, msg->type);
+
+ cserve2_command_run(client, msg->type);
+}
+
+static void
+_client_msg_read(Client *client, int done)
+{
+ client->msg.done += done;
+ if (client->msg.done == client->msg.size)
+ {
+ debug_msg("received", client->msg.buf, client->msg.size);
+ _client_msg_parse(client);
+ _client_msg_free(client);
+ }
+}
+
+void
+cserve2_message_handler(int fd __UNUSED__, Fd_Flags flags, void *data)
+{
+ Client *client = data;
+ int len;
+ int msgsize;
+
+ if (flags & FD_ERROR)
+ {
+ ERR("Error on socket for client: %d", client->id);
+ goto client_close;
+ }
+
+ if (flags & FD_WRITE)
+ cserve2_client_deliver(client);
+
+ if (!(flags & FD_READ))
+ return;
+
+ if (!client->msg.reading)
+ len = cserve2_client_read(client, &msgsize, sizeof(msgsize));
+ else
+ len = cserve2_client_read(client, &client->msg.buf[client->msg.done],
+ client->msg.size - client->msg.done);
+
+ if (!len)
+ {
+ INF("Client %d connection closed.", client->id);
+ goto client_close;
+ }
+
+ if (len < 0)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ {
+ WRN("No data to read but the message handler was called.");
+ return;
+ }
+ WRN("Error when reading message from client: \"%s\"",
+ strerror(errno));
+ // FIXME: Should we close the connection, or just send an ERROR
+ // message?
+ goto client_close;
+ }
+
+ if (!client->msg.reading)
+ _client_msg_allocate_buf(client, msgsize);
+ else
+ _client_msg_read(client, len);
+
+ return;
+
+client_close:
+ if (client->msg.reading)
+ _client_msg_free(client);
+ cserve2_client_del(client);
+}
+
+void
+cserve2_client_deliver(Client *client)
+{
+ size_t sent, size;
+ const char *str;
+
+ if (!client->msg.pending)
+ {
+ Fd_Flags cur_flags;
+ cserve2_fd_watch_flags_get(client->socket, &cur_flags);
+ cur_flags ^= FD_WRITE;
+ cserve2_fd_watch_flags_set(client->socket, cur_flags);
+ return;
+ }
+
+ size = eina_binbuf_length_get(client->msg.pending);
+ str = (const char *)eina_binbuf_string_get(client->msg.pending);
+ sent = cserve2_client_write(client, str, size);
+ if (sent == size)
+ {
+ eina_binbuf_free(client->msg.pending);
+ client->msg.pending = NULL;
+ return;
+ }
+
+ eina_binbuf_remove(client->msg.pending, 0, sent);
+}
+
+ssize_t
+cserve2_client_send(Client *client, const void *data, size_t size)
+{
+ ssize_t sent;
+
+ debug_msg("sent", data, size);
+ if (client->msg.pending)
+ {
+ eina_binbuf_append_length
+ (client->msg.pending, (unsigned char *)data, size);
+ return size;
+ }
+
+ sent = cserve2_client_write(client, data, size);
+ if ((sent < 0) && ((errno != EAGAIN) && (errno != EWOULDBLOCK)))
+ {
+ // FIXME: Big error when writing on the socket to the client,
+ // so we must close the connection to the client and remove
+ // its references inside our cache.
+ WRN("Error on socket with client %d: %s", client->id, strerror(errno));
+ if (client->msg.reading)
+ _client_msg_free(client);
+ cserve2_client_del(client);
+ return sent;
+ }
+ if (sent < 0)
+ sent = 0;
+ if (sent < (int)size)
+ {
+ Fd_Flags cur_flags;
+ client->msg.pending = eina_binbuf_new();
+ eina_binbuf_append_length
+ (client->msg.pending, (unsigned char *)data + sent, size - sent);
+ cserve2_fd_watch_flags_get(client->socket, &cur_flags);
+ cur_flags |= FD_WRITE;
+ cserve2_fd_watch_flags_set(client->socket, cur_flags);
+ }
+ return size;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "evas_cserve2.h"
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+struct _Shm_Mapping
+{
+ const char *name;
+ size_t length;
+ Eina_Inlist *segments;
+};
+
+typedef struct _Shm_Mapping Shm_Mapping;
+
+struct _Shm_Handle
+{
+ EINA_INLIST;
+ Shm_Mapping *mapping;
+ off_t map_offset;
+ off_t image_offset;
+ size_t map_size;
+ size_t image_size;
+};
+
+static int id = 0;
+
+Shm_Handle *
+cserve2_shm_request(size_t size)
+{
+ Shm_Mapping *map;
+ Shm_Handle *shm;
+ char shmname[NAME_MAX];
+ size_t map_size;
+ long pagesize;
+ int fd;
+
+ map = calloc(1, sizeof(Shm_Mapping));
+ if (!map)
+ {
+ ERR("Failed to allocate mapping handler.");
+ return NULL;
+ }
+
+ do {
+ snprintf(shmname, sizeof(shmname), "/evas-shm-img-%d", id++);
+ fd = shm_open(shmname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ if (fd == -1 && errno != EEXIST)
+ {
+ ERR("Failed to create shared memory object '%s': %m", shmname);
+ free(map);
+ return NULL;
+ }
+ } while (fd == -1);
+
+ pagesize = sysconf(_SC_PAGESIZE);
+ if (pagesize < 1)
+ {
+ ERR("sysconf() reported weird value for PAGESIZE, assuming 4096.");
+ pagesize = 4096;
+ }
+
+ map_size = ((size + pagesize - 1) / pagesize) * pagesize;
+
+ if (ftruncate(fd, map_size) == -1)
+ {
+ ERR("Failed to set size of shared file: %m");
+ close(fd);
+ free(map);
+ return NULL;
+ }
+ close(fd);
+
+ map->name = eina_stringshare_add(shmname);
+ map->length = map_size;
+
+ shm = calloc(1, sizeof(Shm_Handle));
+ if (!shm)
+ {
+ ERR("Failed to allocate shared memory handler.");
+ eina_stringshare_del(map->name);
+ free(map);
+ return NULL;
+ }
+
+ map->segments = eina_inlist_append(map->segments, EINA_INLIST_GET(shm));
+ shm->mapping = map;
+ shm->map_offset = 0;
+ shm->image_offset = 0;
+
+ shm->image_size = size;
+ shm->map_size = map_size;
+
+ return shm;
+}
+
+void
+cserve2_shm_unref(Shm_Handle *shm)
+{
+ Shm_Mapping *map = shm->mapping;
+
+ map->segments = eina_inlist_remove(map->segments, EINA_INLIST_GET(shm));
+ free(shm);
+
+ if (map->segments)
+ return;
+
+ shm_unlink(map->name);
+ eina_stringshare_del(map->name);
+ free(map);
+}
+
+const char *
+cserve2_shm_name_get(const Shm_Handle *shm)
+{
+ return shm->mapping->name;
+}
+
+off_t
+cserve2_shm_map_offset_get(const Shm_Handle *shm)
+{
+ return shm->map_offset;
+}
+
+off_t
+cserve2_shm_offset_get(const Shm_Handle *shm)
+{
+ return shm->image_offset;
+}
+
+size_t
+cserve2_shm_map_size_get(const Shm_Handle *shm)
+{
+ return shm->map_size;
+}
+
+size_t
+cserve2_shm_size_get(const Shm_Handle *shm)
+{
+ return shm->image_size;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+static Eina_Hash *loaders = NULL;
+static Eina_List *modules = NULL;
+
+struct ext_loader_s
+{
+ unsigned int length;
+ const char *extension;
+ const char *loader;
+};
+
+#define MATCHING(Ext, Module) \
+ { sizeof (Ext), Ext, Module }
+
+static const struct ext_loader_s map_loaders[] =
+{ /* map extensions to loaders to use for good first-guess tries */
+ MATCHING(".png", "png"),
+ MATCHING(".jpg", "jpeg"),
+ MATCHING(".jpeg", "jpeg"),
+ MATCHING(".jfif", "jpeg"),
+ MATCHING(".eet", "eet"),
+ MATCHING(".edj", "eet"),
+ MATCHING(".eap", "eet"),
+ MATCHING(".edb", "edb"),
+ MATCHING(".xpm", "xpm"),
+ MATCHING(".tiff", "tiff"),
+ MATCHING(".tif", "tiff"),
+ MATCHING(".svg", "svg"),
+ MATCHING(".svgz", "svg"),
+ MATCHING(".svg.gz", "svg"),
+ MATCHING(".gif", "gif"),
+ MATCHING(".pbm", "pmaps"),
+ MATCHING(".pgm", "pmaps"),
+ MATCHING(".ppm", "pmaps"),
+ MATCHING(".pnm", "pmaps"),
+ MATCHING(".bmp", "bmp"),
+ MATCHING(".tga", "tga"),
+ MATCHING(".wbmp", "wbmp"),
+ MATCHING(".ico", "ico"),
+ MATCHING(".cur", "ico"),
+ MATCHING(".psd", "psd")
+};
+
+static const char *loaders_name[] =
+{ /* in order of most likely needed */
+ "png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "pmaps", "bmp", "tga", "wbmp", "ico", "psd", "edb"
+};
+
+Eina_Bool
+evas_cserve2_loader_register(Evas_Loader_Module_Api *api)
+{
+ eina_hash_direct_add(loaders, api->type, api);
+ return EINA_TRUE;
+}
+
+#if defined(__CEGCC__) || defined(__MINGW32CE__)
+# define EVAS_MODULE_NAME_IMAGE_LOADER "loader_%s.dll"
+#elif _WIN32
+# define EVAS_MODULE_NAME_IMAGE_LOADER "module.dll"
+#else
+# define EVAS_MODULE_NAME_IMAGE_LOADER "module.so"
+#endif
+
+static Evas_Loader_Module_Api *
+loader_module_find(const char *type)
+{
+ Evas_Loader_Module_Api *l;
+ Eina_Module *em;
+ char buf[PATH_MAX];
+
+ l = eina_hash_find(loaders, type);
+ if (l) return l;
+
+ /* FIXME: Look in every possible path, but what will those be? */
+ snprintf(buf, sizeof(buf), PACKAGE_LIB_DIR "/evas/cserve2/loaders/%s/%s/%s",
+ type, MODULE_ARCH, EVAS_MODULE_NAME_IMAGE_LOADER);
+
+ em = eina_module_new(buf);
+ if (!em) return NULL;
+
+ if (!eina_module_load(em))
+ {
+ eina_module_free(em);
+ return NULL;
+ }
+
+ l = eina_hash_find(loaders, type);
+ if (l)
+ {
+ modules = eina_list_append(modules, em);
+ return l;
+ }
+
+ eina_module_free(em);
+
+ return NULL;
+}
+
+static Eina_Bool
+command_read(int fd, Slave_Command *cmd, void **params)
+{
+ ssize_t ret;
+ int ints[2], size, got = 0;
+ char *buf;
+
+ ret = read(fd, ints, sizeof(int) * 2);
+ if (ret < (int)sizeof(int) * 2)
+ return EINA_FALSE;
+
+ size = ints[0];
+ buf = malloc(size);
+ if (!buf) return EINA_FALSE;
+
+ do {
+ ret = read(fd, buf + got, size - got);
+ if (ret < 0)
+ {
+ /* EINTR means we were interrupted by a signal before anything
+ * was sent, and if we are back here it means that signal was
+ * not meant for us to die. Any other error here is fatal and
+ * should result in the slave terminating.
+ */
+ if (errno == EINTR)
+ continue;
+ free(buf);
+ return EINA_FALSE;
+ }
+ got += ret;
+ } while (got < size);
+
+ *cmd = ints[1];
+ *params = buf;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+response_send(int fd, Slave_Command cmd, void *resp, int size)
+{
+ int sent = 0, ints[2];
+ const char *data = resp;
+ ssize_t ret;
+
+ ints[0] = size;
+ ints[1] = cmd;
+ ret = write(fd, ints, sizeof(int) * 2);
+ if (ret < 0)
+ return EINA_FALSE;
+ if (!size)
+ return EINA_TRUE;
+ do {
+ ret = write(fd, data + sent, size - sent);
+ if (ret < 0)
+ {
+ /* EINTR means we were interrupted by a signal before anything
+ * was sent, and if we are back here it means that signal was
+ * not meant for us to die. Any other error here is fatal and
+ * should result in the slave terminating.
+ */
+ if (errno == EINTR)
+ continue;
+ return EINA_FALSE;
+ }
+ sent += ret;
+ } while (sent < size);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+error_send(int fd, Error_Type err)
+{
+ return response_send(fd, ERROR, &err, sizeof(Error_Type));
+}
+
+void *
+cserve2_shm_map(const char *name, size_t length, off_t offset)
+{
+ void *map;
+ int fd;
+
+ fd = shm_open(name, O_RDWR, S_IWUSR);
+ if (fd == -1)
+ return MAP_FAILED;
+
+ map = mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, offset);
+
+ close(fd);
+
+ return map;
+}
+
+void
+cserve2_shm_unmap(void *map, size_t length)
+{
+ munmap(map, length);
+}
+
+static Error_Type
+image_open(const char *file, const char *key, Image_Load_Opts *opts, Slave_Msg_Image_Opened *result, const char **use_loader)
+{
+ Evas_Img_Load_Params ilp;
+ Evas_Loader_Module_Api *api;
+ const char *loader = NULL, *end;
+ unsigned int i;
+ int len;
+ int err;
+
+ memset(&ilp, 0, sizeof(ilp));
+
+ if (opts)
+ {
+#define SETOPT(v) ilp.opts.v = opts->v
+ SETOPT(w);
+ SETOPT(h);
+ SETOPT(rx);
+ SETOPT(ry);
+ SETOPT(rw);
+ SETOPT(rh);
+ SETOPT(scale_down_by);
+ SETOPT(dpi);
+ SETOPT(orientation);
+#undef SETOPT
+ ilp.has_opts = EINA_TRUE;
+ }
+
+ if (!*use_loader)
+ goto try_extension;
+
+ loader = *use_loader;
+ api = loader_module_find(loader);
+ if (!api)
+ goto try_extension;
+
+ if (api->head_load(&ilp, file, key, &err))
+ goto done;
+
+try_extension:
+ len = strlen(file);
+ end = file + len;
+ for (i = 0; i < (sizeof (map_loaders) / sizeof(struct ext_loader_s)); i++)
+ {
+ int len2 = strlen(map_loaders[i].extension);
+ if (len2 > len) continue;
+ if (!strcasecmp(end - len2, map_loaders[i].extension))
+ {
+ loader = map_loaders[i].loader;
+ break;
+ }
+ }
+
+ if (!loader)
+ goto try_all_known;
+
+ api = loader_module_find(loader);
+ if (!api)
+ goto try_all_known;
+
+ if (api->head_load(&ilp, file, key, &err))
+ goto done;
+
+try_all_known:
+ for (i = 0; i < (sizeof(loaders_name) / sizeof(loaders_name[0])); i++)
+ {
+ loader = loaders_name[i];
+ api = loader_module_find(loader);
+ if (!api)
+ continue;
+ if (api->head_load(&ilp, file, key, &err))
+ goto done;
+ }
+
+ /* find every module available and try them, even if we don't know they
+ * exist. That will be our generic loader */
+
+ return err;
+
+done:
+ *use_loader = loader;
+
+ result->w = ilp.w;
+ result->h = ilp.h;
+ if ((result->rotated = ilp.rotated))
+ {
+ result->degree = ilp.degree;
+ }
+ if ((result->animated = ilp.animated))
+ {
+ result->frame_count = ilp.frame_count;
+ result->loop_count = ilp.loop_count;
+ result->loop_hint = ilp.loop_hint;
+ }
+ result->scale = ilp.scale;
+ result->alpha = ilp.alpha;
+ return CSERVE2_NONE;
+}
+
+static Error_Type
+image_load(const char *file, const char *key, const char *shmfile, Slave_Msg_Image_Load *params, Slave_Msg_Image_Loaded *result, const char *loader)
+{
+ Evas_Img_Load_Params ilp;
+ Evas_Loader_Module_Api *api;
+ int err;
+ Error_Type ret = CSERVE2_NONE;
+ char *map = cserve2_shm_map(shmfile, params->shm.mmap_size,
+ params->shm.mmap_offset);
+ if (map == MAP_FAILED)
+ return CSERVE2_RESOURCE_ALLOCATION_FAILED;
+
+ memset(&ilp, 0, sizeof(ilp));
+
+ api = loader_module_find(loader);
+ if (!api)
+ {
+ ret = CSERVE2_GENERIC;
+ goto done;
+ }
+
+ ilp.w = params->w;
+ ilp.h = params->h;
+ ilp.alpha = params->alpha;
+#define SETOPT(v) ilp.opts.v = params->opts.v
+ SETOPT(w);
+ SETOPT(h);
+ SETOPT(rx);
+ SETOPT(ry);
+ SETOPT(rw);
+ SETOPT(rh);
+ SETOPT(scale_down_by);
+ SETOPT(dpi);
+ SETOPT(orientation);
+#undef SETOPT
+
+ ilp.buffer = map + params->shm.image_offset;
+ if (!api->data_load(&ilp, file, key, &err))
+ ret = err;
+
+ result->alpha_sparse = ilp.alpha_sparse;
+
+done:
+ cserve2_shm_unmap(map, params->shm.mmap_size);
+
+ return ret;
+}
+
+static void
+handle_image_open(int wfd, void *params)
+{
+ Slave_Msg_Image_Open *p;
+ Slave_Msg_Image_Opened result;
+ Image_Load_Opts *load_opts = NULL;
+ Error_Type err;
+ const char *loader = NULL, *file, *key, *ptr;
+ char *resp;
+ size_t resp_size;
+
+ p = params;
+ file = (const char *)(p + sizeof(Slave_Msg_Image_Open));
+ key = file + strlen(file) + 1;
+ ptr = key + strlen(key) + 1;
+ if (p->has_opts)
+ {
+ load_opts = (Image_Load_Opts *)ptr;
+ ptr += sizeof(Image_Load_Opts);
+ }
+ if (p->has_loader_data)
+ loader = ptr;
+
+ memset(&result, 0, sizeof(result));
+ if ((err = image_open(file, key, load_opts, &result, &loader))
+ != CSERVE2_NONE)
+ {
+ error_send(wfd, err);
+ return;
+ }
+
+ result.has_loader_data = EINA_TRUE;
+
+ resp_size = sizeof(Slave_Msg_Image_Opened) + sizeof(int) + strlen(loader) + 1;
+ resp = alloca(resp_size);
+ memcpy(resp, &result, sizeof(Slave_Msg_Image_Opened));
+ memcpy(resp + sizeof(Slave_Msg_Image_Opened), loader, strlen(loader) + 1);
+ response_send(wfd, IMAGE_OPEN, resp, resp_size);
+}
+
+static void
+handle_image_load(int wfd, void *params)
+{
+ Slave_Msg_Image_Load *load_args = params;
+ Slave_Msg_Image_Loaded resp;
+ Error_Type err;
+ const char *shmfile;
+ const char *file, *key, *loader;
+
+ if (!load_args->has_loader_data)
+ {
+ error_send(wfd, CSERVE2_UNKNOWN_FORMAT);
+ return;
+ }
+
+ memset(&resp, 0, sizeof(resp));
+
+ shmfile = ((const char *)params) + sizeof(Slave_Msg_Image_Load);
+ file = shmfile + strlen(shmfile) + 1;
+ key = file + strlen(file) + 1;
+ loader = key + strlen(key) + 1;
+ if ((err = image_load(file, key, shmfile, load_args, &resp, loader))
+ != CSERVE2_NONE)
+ {
+ error_send(wfd, err);
+ return;
+ }
+
+ response_send(wfd, IMAGE_LOAD, &resp, sizeof(resp));
+}
+
+int main(int c, char **v)
+{
+ int wfd, rfd;
+ Slave_Command cmd;
+ void *params = NULL;
+ Eina_Module *m;
+ Eina_Bool quit = EINA_FALSE;
+
+ if (c < 3)
+ return 1;
+
+ eina_init();
+
+ loaders = eina_hash_string_superfast_new(NULL);
+
+ wfd = atoi(v[1]);
+ rfd = atoi(v[2]);
+
+ while (!quit)
+ {
+ if (!command_read(rfd, &cmd, ¶ms))
+ {
+ error_send(wfd, CSERVE2_INVALID_COMMAND);
+ return 1;
+ }
+ switch (cmd)
+ {
+ case IMAGE_OPEN:
+ handle_image_open(wfd, params);
+ break;
+ case IMAGE_LOAD:
+ handle_image_load(wfd, params);
+ break;
+ case SLAVE_QUIT:
+ quit = EINA_TRUE;
+ break;
+ default:
+ error_send(wfd, CSERVE2_INVALID_COMMAND);
+ }
+ }
+
+ eina_hash_free(loaders);
+
+ EINA_LIST_FREE(modules, m)
+ eina_module_free(m);
+
+ eina_shutdown();
+
+ return 0;
+}
--- /dev/null
+#ifndef _EVAS_CSERVE2_SLAVE_H
+#define _EVAS_CSERVE2_SLAVE_H
+
+#include <Evas.h>
+
+/* begin bunch of stuff from evas_common.h so that we don't need to drag
+ * a lot of useless @SOMETHING_CFLAGS@ around */
+typedef unsigned long long DATA64;
+typedef unsigned int DATA32;
+typedef unsigned short DATA16;
+typedef unsigned char DATA8;
+
+#ifndef WORDS_BIGENDIAN
+/* x86 */
+#define A_VAL(p) (((DATA8 *)(p))[3])
+#define R_VAL(p) (((DATA8 *)(p))[2])
+#define G_VAL(p) (((DATA8 *)(p))[1])
+#define B_VAL(p) (((DATA8 *)(p))[0])
+#define AR_VAL(p) ((DATA16 *)(p)[1])
+#define GB_VAL(p) ((DATA16 *)(p)[0])
+#else
+/* ppc */
+#define A_VAL(p) (((DATA8 *)(p))[0])
+#define R_VAL(p) (((DATA8 *)(p))[1])
+#define G_VAL(p) (((DATA8 *)(p))[2])
+#define B_VAL(p) (((DATA8 *)(p))[3])
+#define AR_VAL(p) ((DATA16 *)(p)[0])
+#define GB_VAL(p) ((DATA16 *)(p)[1])
+#endif
+
+/* if more than 1/ALPHA_SPARSE_INV_FRACTION is "alpha" (1-254) then sparse
+ * alpha flag gets set */
+#define ALPHA_SPARSE_INV_FRACTION 3
+
+#define IMG_MAX_SIZE 65000
+
+#define IMG_TOO_BIG(w, h) \
+ ((((unsigned long long)w) * ((unsigned long long)h)) >= \
+ ((1ULL << (29 * (sizeof(void *) / 4))) - 2048))
+
+#define RGB_JOIN(r,g,b) \
+ (((r) << 16) + ((g) << 8) + (b))
+
+#define ARGB_JOIN(a,r,g,b) \
+ (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
+/* end bunchf of stuff from evas_common.h */
+
+typedef struct _Evas_Loader_Module_Api Evas_Loader_Module_Api;
+typedef struct _Evas_Img_Load_Params Evas_Img_Load_Params;
+
+#define EVAS_CSERVE2_MODULE_API_VERSION 1
+struct _Evas_Loader_Module_Api {
+ int version;
+ const char *type;
+ Eina_Bool (*head_load)(Evas_Img_Load_Params *p, const char *file, const char *key, int *error);
+ Eina_Bool (*data_load)(Evas_Img_Load_Params *p, const char *file, const char *key, int *error);
+};
+
+struct _Evas_Img_Load_Params {
+ unsigned int w, h;
+ unsigned int degree;
+ unsigned int scale;
+ int frame_count;
+ int loop_count;
+ int loop_hint;
+ struct {
+ unsigned int w, h;
+ unsigned int rx, ry, rw, rh;
+ int scale_down_by;
+ double dpi;
+ Eina_Bool orientation;
+ } opts;
+ void *buffer;
+ Eina_Bool has_opts : 1;
+ Eina_Bool rotated : 1;
+ Eina_Bool alpha : 1;
+ Eina_Bool alpha_sparse : 1;
+ Eina_Bool animated : 1;
+};
+
+EAPI Eina_Bool evas_cserve2_loader_register(Evas_Loader_Module_Api *api);
+
+EAPI void evas_cserve2_image_premul(Evas_Img_Load_Params *ilp);
+EAPI void evas_cserve2_image_alpha_sparse_set(Evas_Img_Load_Params *ilp);
+
+#endif /* _EVAS_CSERVE2_SLAVE_H */
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "evas_cserve2.h"
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+struct _Slave_Proc
+{
+ pid_t pid;
+ const char *name;
+ int write_fd;
+ int read_fd;
+ Slave_Read_Cb read_cb;
+ Slave_Dead_Cb dead_cb;
+ const void *data;
+ Eina_Binbuf *pending;
+
+ struct {
+ int size;
+ int read_size;
+ Slave_Command cmd;
+ char *buf;
+ } read;
+
+ Eina_Bool killed : 1;
+};
+
+static Eina_List *slaves;
+
+static Slave_Proc *
+_child_find(pid_t pid)
+{
+ Eina_List *l;
+ Slave_Proc *s;
+
+ EINA_LIST_FOREACH(slaves, l, s)
+ if (s->pid == pid)
+ return s;
+ return NULL;
+}
+
+static void
+_slave_free(Slave_Proc *s)
+{
+ if (s->write_fd)
+ close(s->write_fd);
+ if (s->read_fd)
+ {
+ cserve2_fd_watch_del(s->read_fd);
+ close(s->read_fd);
+ }
+
+ free(s->read.buf);
+
+ if (s->pending)
+ eina_binbuf_free(s->pending);
+
+ if (s->dead_cb)
+ s->dead_cb(s, (void *)s->data);
+
+ eina_stringshare_del(s->name);
+
+ free(s);
+}
+
+static void
+_slave_dead_cb(int pid, int status __UNUSED__)
+{
+ Slave_Proc *s;
+
+ DBG("Child dead with pid '%d'.", pid);
+ s = _child_find(pid);
+ if (!s)
+ {
+ ERR("Unknown child dead '%d'.", pid);
+ return;
+ }
+
+ slaves = eina_list_remove(slaves, s);
+ _slave_free(s);
+}
+
+static size_t
+_slave_write(Slave_Proc *s, const char *data, size_t size)
+{
+ size_t sent = 0;
+
+ do
+ {
+ ssize_t ret;
+ ret = write(s->write_fd, data + sent, size - sent);
+ if (ret == -1)
+ {
+ if (errno == EAGAIN)
+ break;
+ if (errno == EPIPE)
+ {
+ WRN("Slave unexpectedly gone.");
+ /* handle dead? */
+ break;
+ }
+ }
+ sent += ret;
+ } while(sent < size);
+
+ return sent;
+}
+
+static void
+_slave_write_cb(int fd __UNUSED__, Fd_Flags flags __UNUSED__, void *data)
+{
+ Slave_Proc *s = data;
+ size_t sent;
+ size_t size;
+ const char *str;
+
+ size = eina_binbuf_length_get(s->pending);
+ str = (const char *)eina_binbuf_string_get(s->pending);
+ sent = _slave_write(s, str, size);
+ if (sent == size)
+ {
+ eina_binbuf_free(s->pending);
+ s->pending = NULL;
+ cserve2_fd_watch_del(s->write_fd);
+ return;
+ }
+
+ eina_binbuf_remove(s->pending, 0, sent);
+}
+
+static void
+_slave_read_clear(Slave_Proc *s)
+{
+ s->read.buf = NULL;
+ s->read.cmd = 0;
+ s->read.read_size = s->read.size = 0;
+}
+
+static void
+_slave_read_cb(int fd, Fd_Flags flags, void *data)
+{
+ Slave_Proc *s = data;
+ Eina_Bool done = EINA_FALSE;
+
+ /* handle error */
+ if (!(flags & FD_READ))
+ return;
+
+ if (!s->read.size)
+ {
+ int ints[2];
+ ssize_t ret;
+
+ ret = read(fd, ints, sizeof(int) * 2);
+ if (ret < (int)sizeof(int) * 2)
+ {
+ return;
+ }
+ s->read.size = ints[0];
+ s->read.cmd = ints[1];
+ if (s->read.size)
+ s->read.buf = malloc(s->read.size);
+ else
+ done = EINA_TRUE;
+ }
+
+ if (s->read.buf)
+ {
+ ssize_t ret;
+ do {
+ char *p = s->read.buf + s->read.read_size;
+ int sz = s->read.size - s->read.read_size;
+ ret = read(fd, p, sz);
+ if (ret < 0)
+ {
+ if (errno == EAGAIN)
+ break;
+ }
+ s->read.read_size += ret;
+ } while(s->read.read_size < s->read.size);
+
+ if (s->read.read_size == s->read.size)
+ done = EINA_TRUE;
+ }
+
+ if (done)
+ {
+ s->read_cb(s, s->read.cmd, s->read.buf, (void *)s->data);
+ _slave_read_clear(s);
+ }
+}
+
+Eina_Bool
+cserve2_slaves_init(void)
+{
+ cserve2_on_child_dead_set(_slave_dead_cb);
+ return EINA_TRUE;
+}
+
+void
+cserve2_slaves_shutdown(void)
+{
+ Slave_Proc *s;
+
+ cserve2_on_child_dead_set(NULL);
+
+ if (!slaves)
+ return;
+
+ DBG("Shutting down slaves subsystem with %d slaves alive!",
+ eina_list_count(slaves));
+
+ EINA_LIST_FREE(slaves, s)
+ {
+ kill(s->pid, SIGKILL);
+ _slave_free(s);
+ }
+}
+
+static const char *
+_slave_path_get(const char *name)
+{
+ char buf[PATH_MAX], cwd[PATH_MAX];
+ struct stat st;
+
+ if (name[0] == '/')
+ {
+ if (access(name, X_OK))
+ return NULL;
+ return eina_stringshare_add(name);
+ }
+
+ getcwd(cwd, sizeof(cwd));
+ snprintf(buf, sizeof(buf), "%s/%s", cwd, name);
+ if (!access(buf, X_OK))
+ return eina_stringshare_add(buf);
+
+ snprintf(buf, sizeof(buf), PACKAGE_LIBEXEC_DIR"/%s", name);
+ if (!access(buf, X_OK))
+ return eina_stringshare_add(buf);
+
+ return NULL;
+}
+
+Slave_Proc *
+cserve2_slave_run(const char *exe, Slave_Read_Cb read_cb, Slave_Dead_Cb dead_cb, const void *data)
+{
+ Slave_Proc *s;
+ pid_t pid;
+ int child[2], parent[2];
+ int flags;
+ const char *name;
+
+ name = _slave_path_get(exe);
+ if (!name)
+ {
+ ERR("Cannot execute slave '%s'. Not found or not executable.", exe);
+ return NULL;
+ }
+ DBG("Running slave '%s', resolved to path: %s", exe, name);
+
+ s = calloc(1, sizeof(Slave_Proc));
+ if (!s)
+ {
+ ERR("Could not create Slave_Proc handler.");
+ eina_stringshare_del(name);
+ return NULL;
+ }
+
+ if (pipe(child))
+ {
+ ERR("Could not create pipes for child.");
+ eina_stringshare_del(name);
+ free(s);
+ return NULL;
+ }
+
+ if (pipe(parent))
+ {
+ ERR("Could not create pipes for parent.");
+ eina_stringshare_del(name);
+ free(s);
+ close(child[0]);
+ close(child[1]);
+ return NULL;
+ }
+
+ pid = fork();
+ if (pid < 0)
+ {
+ ERR("Could not create sub process.");
+ eina_stringshare_del(name);
+ close(child[0]);
+ close(child[1]);
+ close(parent[0]);
+ close(parent[1]);
+ free(s);
+ return NULL;
+ }
+
+ if (!pid)
+ {
+ char *args[4], readfd[12], writefd[12];
+
+ close(child[1]);
+ close(parent[0]);
+
+ sprintf(readfd, "%d", child[0]);
+ sprintf(writefd, "%d", parent[1]);
+ args[0] = (char *)name;
+ args[1] = writefd;
+ args[2] = readfd;
+ args[3] = NULL;
+ execvp(name, args);
+ /* we only get here if execvp fails, which should not
+ * happen and if it does, it's baaaaaaaaad */
+ ERR("execvp() for slave at: '%s' failed! '%m'", name);
+ exit(1);
+ }
+
+ s->pid = pid;
+ s->name = name;
+ s->write_fd = child[1];
+ flags = fcntl(s->write_fd, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(s->write_fd, F_SETFL, flags);
+ s->read_fd = parent[0];
+ flags = fcntl(s->read_fd, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(s->read_fd, F_SETFL, flags);
+ s->read_cb = read_cb;
+ s->dead_cb = dead_cb;
+ s->data = data;
+ cserve2_fd_watch_add(s->read_fd, FD_READ, _slave_read_cb, s);
+
+ close(child[0]);
+ close(parent[1]);
+
+ slaves = eina_list_append(slaves, s);
+
+ return s;
+}
+
+static void
+_slave_send_aux(Slave_Proc *s, const char *data, size_t size)
+{
+ size_t sent;
+
+ if (s->pending)
+ {
+ eina_binbuf_append_length(s->pending, (unsigned char *)data, size);
+ return;
+ }
+
+ sent = _slave_write(s, data, size);
+ if (sent < size)
+ {
+ s->pending = eina_binbuf_new();
+ eina_binbuf_append_length(s->pending, (unsigned char *)data + sent,
+ size - sent);
+ cserve2_fd_watch_add(s->write_fd, FD_WRITE, _slave_write_cb, s);
+ }
+}
+
+void
+cserve2_slave_send(Slave_Proc *s, Slave_Command cmd, const char *data, size_t size)
+{
+ int ints[2];
+
+ ints[0] = size;
+ ints[1] = cmd;
+ _slave_send_aux(s, (char *)ints, sizeof(int) * 2);
+ if (size)
+ _slave_send_aux(s, (char *)data, size);
+}
+
+void
+cserve2_slave_kill(Slave_Proc *s)
+{
+ if (s->killed)
+ {
+ if (!kill(s->pid, 0))
+ DBG("Slave %p(%d) requested to kill, but it's still alive.",
+ s, s->pid);
+ }
+
+ s->killed = EINA_TRUE;
+ kill(s->pid, SIGTERM);
+}
--- /dev/null
+#include "evas_cserve2_slave.h"
+
+static unsigned int
+evas_cserve2_convert_argb_premul(unsigned int *data, unsigned int len)
+{
+ unsigned int *de = data + len;
+ unsigned int nas = 0;
+
+ while (data < de)
+ {
+ unsigned int a = 1 + (*data >> 24);
+
+ *data = (*data & 0xff000000) +
+ (((((*data) >> 8) & 0xff) * a) & 0xff00) +
+ (((((*data) & 0x00ff00ff) * a) >> 8) & 0x00ff00ff);
+ data++;
+
+ if ((a == 1) || (a == 256))
+ nas++;
+ }
+
+ return nas;
+}
+
+EAPI void
+evas_cserve2_image_premul(Evas_Img_Load_Params *ilp)
+{
+ unsigned int nas;
+
+ if (!ilp->alpha) return;
+
+ nas = evas_cserve2_convert_argb_premul(ilp->buffer, ilp->w * ilp->h);
+ if ((ALPHA_SPARSE_INV_FRACTION * nas) >= (ilp->w * ilp->h))
+ ilp->alpha_sparse = EINA_TRUE;
+}
+
+EAPI void
+evas_cserve2_imave_alpha_sparse_set(Evas_Img_Load_Params *ilp)
+{
+ unsigned int *s, *se;
+ unsigned int nas = 0;
+ unsigned int len = ilp->w * ilp->h;
+
+ if (!ilp->alpha) return;
+
+ s = ilp->buffer;
+ se = s + len;
+ while (s < se)
+ {
+ unsigned int p = *s & 0xff000000;
+
+ if (!p || (p == 0xff000000))
+ nas++;
+ s++;
+ }
+ if ((ALPHA_SPARSE_INV_FRACTION * nas) >= len)
+ ilp->alpha_sparse = EINA_TRUE;
+}
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS =
+
+if BUILD_LOADER_BMP
+SUBDIRS += bmp
+endif
+
+if BUILD_LOADER_EET
+SUBDIRS += eet
+endif
+
+if BUILD_LOADER_ICO
+SUBDIRS += ico
+endif
+
+if BUILD_LOADER_JPEG
+SUBDIRS += jpeg
+endif
+
+if BUILD_LOADER_PMAPS
+SUBDIRS += pmaps
+endif
+
+if BUILD_LOADER_PNG
+SUBDIRS += png
+endif
+
+if BUILD_LOADER_PSD
+SUBDIRS += psd
+endif
+
+if BUILD_LOADER_TGA
+SUBDIRS += tga
+endif
+
+if BUILD_LOADER_TIFF
+SUBDIRS += tiff
+endif
+
+if BUILD_LOADER_WBMP
+SUBDIRS += wbmp
+endif
+
+if BUILD_LOADER_XPM
+SUBDIRS += xpm
+endif
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_BMP
+#if !EVAS_STATIC_BUILD_BMP
+
+pkgdir = $(libdir)/evas/cserve2/loaders/bmp/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_bmp.c
+
+module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@ -lm
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_bmp.la
+#libevas_loader_bmp_la_SOURCES = evas_image_load_bmp.c
+#libevas_loader_bmp_la_LIBADD =
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include <math.h>
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+static Eina_Bool
+read_short(unsigned char *map, size_t length, size_t *position, short *ret)
+{
+ unsigned char b[2];
+
+ if (*position + 2 > length) return EINA_FALSE;
+ b[0] = map[(*position)++];
+ b[1] = map[(*position)++];
+ *ret = (b[1] << 8) | b[0];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
+{
+ unsigned char b[2];
+
+ if (*position + 2 > length) return EINA_FALSE;
+ b[0] = map[(*position)++];
+ b[1] = map[(*position)++];
+ *ret = (b[1] << 8) | b[0];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_int(unsigned char *map, size_t length, size_t *position, int *ret)
+{
+ unsigned char b[4];
+ int i;
+
+ if (*position + 4 > length) return EINA_FALSE;
+ for (i = 0; i < 4; i++)
+ b[i] = map[(*position)++];
+ *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
+{
+ unsigned char b[4];
+ int i;
+
+ if (*position + 4 > length) return EINA_FALSE;
+ for (i = 0; i < 4; i++)
+ b[i] = map[(*position)++];
+ *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
+{
+ if (*position + 1 > length) return EINA_FALSE;
+ *ret = map[(*position)++];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_skip(size_t length, size_t *position, int skip)
+{
+ if (*position + skip > length) return EINA_FALSE;
+ *position += skip;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
+{
+ if (*position + size > length) return EINA_FALSE;
+ memcpy(buffer, map + *position, size);
+ *position += size;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+evas_image_load_file_head_bmp(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ Eina_File *f;
+ void *map = NULL;
+ size_t position = 0;
+ char hasa = 0;
+ int w = 0, h = 0, bit_count = 0, image_size = 0, comp = 0;
+ unsigned int offset, head_size, amask = 0;
+ int fsize = 0;
+ unsigned int bmpsize;
+ unsigned short res1, res2;
+
+ f = eina_file_open(file, 0);
+ if (!f)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ fsize = eina_file_size_get(f);
+ if (fsize < 2) goto close_file;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map) goto close_file;
+
+ if (strncmp(map, "BM", 2)) goto close_file; // magic number
+ position += 2;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ if (!read_uint(map, fsize, &position, &bmpsize)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &res1)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &res2)) goto close_file;
+ if (!read_uint(map, fsize, &position, &offset)) goto close_file;
+ if (!read_uint(map, fsize, &position, &head_size)) goto close_file;
+ if (head_size == 12) // OS/2 V1 + Windows 3.0
+ {
+ short tmp;
+
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ w = tmp; // width
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ h = tmp; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8 & 24
+ }
+ else if (head_size == 64) // OS/2 V2
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ w = tmp2; // width
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ h = tmp2; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ comp = tmp2; // compression method
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ image_size = tmp2; // bitmap data size
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_skip(fsize, &position, 24)) goto close_file; // skip unused header
+ if (image_size == 0) image_size = fsize - offset;
+ }
+ else if (head_size == 40) // Windows 3.0 + (v3)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ w = tmp2; // width
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ h = tmp2; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ comp = tmp2; // compression method
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ image_size = tmp2; // bitmap data size
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (image_size == 0) image_size = fsize - offset;
+ if ((comp == 0) && (bit_count == 32)) hasa = 1; // GIMP seems to store it this way
+ }
+ else if (head_size == 108) // Windows 95/NT4 + (v4)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ w = tmp2; // width
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ h = tmp2; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ comp = tmp2; // compression method
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ image_size = tmp2; // bitmap data size
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //rmask = tmp2; // red mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //gmask = tmp2; // green mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //bmask = tmp2; // blue mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ amask = tmp2; // alpha mask
+ if (!read_skip(fsize, &position, 36)) goto close_file; // skip unused cie
+ if (!read_skip(fsize, &position, 12)) goto close_file; // skip unused gamma
+ if (image_size == 0) image_size = fsize - offset;
+ if ((amask) && (bit_count == 32)) hasa = 1;
+ }
+ else if (head_size == 124) // Windows 98/2000 + (v5)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ w = tmp2; // width
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ h = tmp2; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ comp = tmp2; // compression method
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //image_size = tmp2; // bitmap data size
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //rmask = tmp2; // red mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //gmask = tmp2; // green mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //bmask = tmp2; // blue mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ amask = tmp2; // alpha mask
+ if (!read_skip(fsize, &position, 36)) goto close_file; // skip unused cie
+ if (!read_skip(fsize, &position, 12)) goto close_file; // skip unused gamma
+ if (!read_skip(fsize, &position, 16)) goto close_file; // skip others
+ if (image_size == 0) image_size = fsize - offset;
+ if ((amask) && (bit_count == 32)) hasa = 1;
+ }
+ else
+ goto close_file;
+
+ if (h < 0)
+ {
+ h = -h;
+ //right_way_up = 1;
+ }
+
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ {
+ if (IMG_TOO_BIG(w, h))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ /* It is not bad idea that bmp loader support scale down decoding
+ * because of memory issue in mobile world.*/
+ if (ilp->opts.scale_down_by > 1)
+ {
+ w /= ilp->opts.scale_down_by;
+ h /= ilp->opts.scale_down_by;
+ }
+
+ if (bit_count < 16)
+ {
+ //if ((palette_size < 0) || (palette_size > 256)) pal_num = 256;
+ //else pal_num = palette_size;
+ if (bit_count == 1)
+ {
+ if (comp == 0) // no compression
+ {
+ }
+ else
+ goto close_file;
+ }
+ else if (bit_count == 4)
+ {
+ if (comp == 0) // no compression
+ {
+ }
+ else if (comp == 2) // rle 4bit/pixel
+ {
+ }
+ else
+ goto close_file;
+ }
+ else if (bit_count == 8)
+ {
+ if (comp == 0) // no compression
+ {
+ }
+ else if (comp == 1) // rle 8bit/pixel
+ {
+ }
+ else
+ goto close_file;
+ }
+ }
+ else if ((bit_count == 16) || (bit_count == 24) || (bit_count == 32))
+ {
+ if (comp == 0) // no compression
+ {
+ // handled
+ }
+ else if (comp == 3) // bit field
+ {
+ // handled
+ }
+ else if (comp == 4) // jpeg - only printer drivers
+ goto close_file;
+ else if (comp == 3) // png - only printer drivers
+ goto close_file;
+ else
+ goto close_file;
+ }
+ else
+ goto close_file;
+
+ ilp->w = w;
+ ilp->h = h;
+ if (hasa) ilp->alpha = 1;
+
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+
+ close_file:
+ if (map) eina_file_map_free(f, map);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_bmp(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ Eina_File *f;
+ void *map = NULL;
+ size_t position = 0;
+ unsigned char *buffer = NULL, *buffer_end = NULL, *p;
+ char hasa = 0;
+ int x = 0, y = 0, w = 0, h = 0, bit_count = 0, image_size = 0,
+ comp = 0, palette_size = -1;
+ unsigned int offset = 0, head_size = 0;
+ unsigned int *pal = NULL, pal_num = 0, *pix = NULL, *surface = NULL, fix,
+ rmask = 0, gmask = 0, bmask = 0, amask = 0;
+ int right_way_up = 0;
+ unsigned char r, g, b, a;
+ int fsize = 0;
+ unsigned int bmpsize;
+ unsigned short res1, res2;
+
+ /* for scale decoding */
+ unsigned int *scale_surface = NULL, *scale_pix = NULL;
+ int scale_ratio = 1, image_w = 0, image_h = 0;
+ int row_size = 0; /* Row size is rounded up to a multiple of 4bytes */
+ int read_line = 0; /* total read line */
+
+ f = eina_file_open(file, 0);
+ if (!f)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ fsize = eina_file_size_get(f);
+ if (fsize < 2) goto close_file;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map) goto close_file;
+
+ if (strncmp(map, "BM", 2)) goto close_file; // magic number
+ position += 2;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ if (!read_uint(map, fsize, &position, &bmpsize)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &res1)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &res2)) goto close_file;
+ if (!read_uint(map, fsize, &position, &offset)) goto close_file;
+ if (!read_uint(map, fsize, &position, &head_size)) goto close_file;
+ image_size = fsize - offset;
+ if (image_size < 1) goto close_file;
+
+ if (head_size == 12) // OS/2 V1 + Windows 3.0
+ {
+ short tmp;
+
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ w = tmp; // width
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ h = tmp; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8 & 24
+ }
+ else if (head_size == 64) // OS/2 V2
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ w = tmp2; // width
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ h = tmp2; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ comp = tmp2; // compression method
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ image_size = tmp2; // bitmap data size
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_skip(fsize, &position, 24)) goto close_file; // skip unused header
+ if (image_size == 0) image_size = fsize - offset;
+ }
+ else if (head_size == 40) // Windows 3.0 + (v3)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ w = tmp2; // width
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ h = tmp2; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ comp = tmp2; // compression method
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ image_size = tmp2; // bitmap data size
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (image_size == 0) image_size = fsize - offset;
+ if ((comp == 0) && (bit_count == 32)) hasa = 1; // GIMP seems to store it this way
+ }
+ else if (head_size == 108) // Windows 95/NT4 + (v4)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ w = tmp2; // width
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ h = tmp2; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ comp = tmp2; // compression method
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ image_size = tmp2; // bitmap data size
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ rmask = tmp2; // red mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ gmask = tmp2; // green mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ bmask = tmp2; // blue mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ amask = tmp2; // alpha mask
+ if (!read_skip(fsize, &position, 36)) goto close_file; // skip unused cie
+ if (!read_skip(fsize, &position, 12)) goto close_file; // skip unused gamma
+ if (image_size == 0) image_size = fsize - offset;
+ if ((amask) && (bit_count == 32)) hasa = 1;
+ }
+ else if (head_size == 124) // Windows 98/2000 + (v5)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ w = tmp2; // width
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ h = tmp2; // height
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, &position, &tmp)) goto close_file;
+ bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ comp = tmp2; // compression method
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ image_size = tmp2; // bitmap data size
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ rmask = tmp2; // red mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ gmask = tmp2; // green mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ bmask = tmp2; // blue mask
+ if (!read_int(map, fsize, &position, &tmp2)) goto close_file;
+ amask = tmp2; // alpha mask
+ if (!read_skip(fsize, &position, 36)) goto close_file; // skip unused cie
+ if (!read_skip(fsize, &position, 12)) goto close_file; // skip unused gamma
+ if (!read_skip(fsize, &position, 16)) goto close_file; // skip others
+ if (image_size == 0) image_size = fsize - offset;
+ if ((amask) && (bit_count == 32)) hasa = 1;
+ }
+ else
+ goto close_file;
+
+ if (h < 0)
+ {
+ h = -h;
+ right_way_up = 1;
+ }
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ {
+ if (IMG_TOO_BIG(w, h))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ /* It is not bad idea that bmp loader support scale down decoding
+ * because of memory issue in mobile world. */
+ if (ilp->opts.scale_down_by > 1)
+ scale_ratio = ilp->opts.scale_down_by;
+ image_w = w;
+ image_h = h;
+
+ if (scale_ratio > 1)
+ {
+ w /= scale_ratio;
+ h /= scale_ratio;
+
+ if ((w < 1) || (h < 1) )
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ }
+
+ if ((w != (int)ilp->w) || (h != (int)ilp->h))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ surface = ilp->buffer;
+ if (!surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ row_size = ceil((double)(image_w * bit_count) / 32) * 4;
+
+ if (bit_count < 16)
+ {
+ unsigned int i;
+
+ if (bit_count == 1)
+ {
+ if ((palette_size <= 0) || (palette_size > 2)) pal_num = 2;
+ else pal_num = palette_size;
+ }
+ else if (bit_count == 4)
+ {
+ if ((palette_size <= 0) || (palette_size > 16)) pal_num = 16;
+ else pal_num = palette_size;
+ }
+ else if (bit_count == 8)
+ {
+ if ((palette_size <= 0) || (palette_size > 256)) pal_num = 256;
+ else pal_num = palette_size;
+ }
+ pal = alloca(256 * 4);
+ for (i = 0; i < pal_num; i++)
+ {
+ if (!read_uchar(map, fsize, &position, &b)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &g)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &r)) goto close_file;
+ if ((head_size != 12) /*&& (palette_size != 0)*/)
+ { // OS/2 V1 doesn't do the pad byte
+ if (!read_uchar(map, fsize, &position, &a)) goto close_file;
+ }
+ a = 0xff; // fillin a as solid for paletted images
+ pal[i] = ARGB_JOIN(a, r, g, b);
+ }
+ position = offset;
+
+ if ((scale_ratio == 1) || (comp !=0))
+ buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ else
+ {
+ scale_surface = malloc(image_w * sizeof(DATA32)); //for one line decoding
+ if (!scale_surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ buffer = malloc(row_size); // scale down is usually set because of memory issue, so read line by line
+ }
+
+ if (!buffer)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ if ((scale_ratio == 1) || (comp !=0))
+ buffer_end = buffer + image_size;
+ else
+ buffer_end = buffer + row_size;
+ p = buffer;
+
+ if ((scale_ratio == 1) || (comp !=0))
+ {
+ if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
+ }
+ else
+ {
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ }
+
+ if (bit_count == 1)
+ {
+ if (comp == 0) // no compression
+ {
+ pix = surface;
+
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ if (scale_ratio > 1) pix = scale_surface; // one line decoding
+
+ for (x = 0; x < image_w; x++)
+ {
+ if ((x & 0x7) == 0x0)
+ {
+ *pix = pal[*p >> 7];
+ }
+ else if ((x & 0x7) == 0x1)
+ {
+ *pix = pal[(*p >> 6) & 0x1];
+ }
+ else if ((x & 0x7) == 0x2)
+ {
+ *pix = pal[(*p >> 5) & 0x1];
+ }
+ else if ((x & 0x7) == 0x3)
+ {
+ *pix = pal[(*p >> 4) & 0x1];
+ }
+ else if ((x & 0x7) == 0x4)
+ {
+ *pix = pal[(*p >> 3) & 0x1];
+ }
+ else if ((x & 0x7) == 0x5)
+ {
+ *pix = pal[(*p >> 2) & 0x1];
+ }
+ else if ((x & 0x7) == 0x6)
+ {
+ *pix = pal[(*p >> 1) & 0x1];
+ }
+ else
+ {
+ *pix = pal[*p & 0x1];
+ p++;
+ }
+ if (p >= buffer_end) break;
+ pix++;
+ }
+
+ if (scale_ratio > 1)
+ {
+ if (!right_way_up) scale_pix = surface + ((h - 1 - y) * w);
+ else scale_pix = surface + (y * w);
+
+ pix = scale_surface;
+ for (x = 0; x < w; x++)
+ {
+ *scale_pix = *pix;
+ scale_pix ++;
+ pix += scale_ratio;
+ }
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ if ((x & 0x7) != 0) p++;
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ else if (bit_count == 4)
+ {
+ if (comp == 0) // no compression
+ {
+ pix = surface;
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ if (scale_ratio > 1) pix = scale_surface; // one line decoding
+ for (x = 0; x < image_w; x++)
+ {
+ if ((x & 0x1) == 0x1)
+ {
+ *pix = pal[*p & 0x0f];
+ p++;
+ }
+ else
+ {
+ *pix = pal[*p >> 4];
+ }
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ if (!right_way_up) scale_pix = surface + ((h - 1 - y) * w);
+ else scale_pix = surface + (y * w);
+
+ pix = scale_surface;
+ for (x = 0; x < w; x++)
+ {
+ *scale_pix = *pix;
+ scale_pix ++;
+ pix += scale_ratio;
+ }
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ if ((x & 0x1) != 0) p++;
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (comp == 2) // rle 4bit/pixel
+ {
+ int count = 0, done = 0, wpad;
+ int scale_x = 0, scale_y = 0;
+ Eina_Bool scale_down_line = EINA_TRUE;
+
+ pix = surface;
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ wpad = ((image_w + 1) / 2) * 2;
+ while (p < buffer_end)
+ {
+ if (p[0])
+ {
+ if (scale_down_line)
+ {
+ if ((x + p[0]) <= wpad)
+ {
+ unsigned int col1 = pal[p[1] >> 4];
+ unsigned int col2 = pal[p[1] & 0xf];
+
+ count = p[0] / 2;
+ while (count > 0)
+ {
+ if (x < w)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < w))
+ {
+ *pix = col1;
+ pix++;
+ scale_x++;
+ }
+ x++;
+ }
+ if (x < w)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < w))
+ {
+ *pix = col2;
+ pix++;
+ scale_x++;
+ }
+ x++;
+ }
+ count--;
+ }
+ if (p[0] & 0x1)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < w))
+ {
+ *pix = col1;
+ pix++;
+ scale_x++;
+ }
+ x++;
+ }
+ }
+ }
+ p += 2;
+ }
+ else
+ {
+ switch (p[1])
+ {
+ case 0: // EOL
+ x = 0;
+ scale_x = 0;
+ y++;
+ if ((y % scale_ratio) == 0)
+ {
+ scale_y++;
+ scale_down_line = EINA_TRUE;
+ if (!right_way_up)
+ pix = surface + ((h - 1 - scale_y) * w);
+ else
+ pix = surface + (scale_y * w);
+ }
+ else
+ scale_down_line = EINA_FALSE;
+ if (scale_y >= h)
+ {
+ p = buffer_end;
+ }
+ p += 2;
+ break;
+ case 1: // EOB
+ p = buffer_end;
+ break;
+ case 2: // DELTA
+ x += p[2];
+ y += p[3];
+ scale_x = x / scale_ratio;
+ scale_y = y / scale_ratio;
+ if ((scale_x >= w) || (scale_y >= h))
+ {
+ p = buffer_end;
+ }
+ if (!right_way_up)
+ pix = surface + scale_x + ((h - 1 - scale_y) * w);
+ else
+ pix = surface + scale_x + (scale_y * w);
+ p += 4;
+ break;
+ default:
+ count = p[1];
+ if (((p + count) > buffer_end) ||
+ ((x + count) > w))
+ {
+ p = buffer_end;
+ break;
+ }
+ p += 2;
+ done = count;
+ count /= 2;
+ while (count > 0)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < w))
+ {
+ *pix = pal[*p >> 4];
+ pix++;
+ scale_x++;
+ }
+ x++;
+ if (((x % scale_ratio) == 0) && (scale_x < w))
+ {
+ *pix = pal[*p & 0xf];
+ pix++;
+ scale_x++;
+ }
+ x++;
+
+ p++;
+ count--;
+ }
+
+ if (done & 0x1)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < w))
+ {
+ *pix = pal[*p >> 4];
+ scale_x++;
+ }
+ x++;
+ p++;
+ }
+ if ((done & 0x3) == 0x1)
+ p += 2;
+ else if ((done & 0x3) == 0x2)
+ p += 1;
+ break;
+ }
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ else if (bit_count == 8)
+ {
+ if (comp == 0) // no compression
+ {
+ pix = surface;
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ for (x = 0; x < w; x++)
+ {
+ *pix = pal[*p];
+ p += scale_ratio;
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (comp == 1) // rle 8bit/pixel
+ {
+ int count = 0, done = 0;
+ int scale_x = 0, scale_y = 0;
+ Eina_Bool scale_down_line = EINA_TRUE;
+
+ pix = surface;
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+
+ while (p < buffer_end)
+ {
+ if (p[0])
+ {
+ if (scale_down_line)
+ {
+ if ((x + p[0]) <= image_w)
+ {
+ unsigned int col = pal[p[1]];
+
+ count = p[0];
+ while (count > 0)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < w))
+ {
+ *pix = col;
+ pix++;
+ scale_x ++;
+ }
+ x++;
+ count--;
+ }
+ }
+ }
+ p += 2;
+ }
+ else
+ {
+ switch (p[1])
+ {
+ case 0: // EOL
+ x = 0;
+ scale_x = 0;
+ y++;
+ if ((y % scale_ratio) == 0)
+ {
+ scale_y++;
+ scale_down_line = EINA_TRUE;
+ if (!right_way_up)
+ pix = surface + ((h - 1 - scale_y) * w);
+ else
+ pix = surface + (scale_y * w);
+ }
+ else
+ scale_down_line = EINA_FALSE;
+
+ if (scale_y >= h)
+ {
+ p = buffer_end;
+ }
+ p += 2;
+ break;
+ case 1: // EOB
+ p = buffer_end;
+ break;
+ case 2: // DELTA
+ x += p[2];
+ y += p[3];
+ scale_x = x / scale_ratio;
+ scale_y = y / scale_ratio;
+ if ((scale_x >= w) || (scale_y >= h))
+ {
+ p = buffer_end;
+ }
+ if (!right_way_up)
+ pix = surface + scale_x + ((h - 1 - scale_y) * w);
+ else
+ pix = surface + scale_x + (scale_y * w);
+ p += 4;
+ break;
+ default:
+ count = p[1];
+ if (((p + count) > buffer_end) ||
+ ((x + count) > image_w))
+ {
+ p = buffer_end;
+ break;
+ }
+ p += 2;
+ done = count;
+ while (count > 0)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < w))
+ {
+ *pix = pal[*p];
+ pix++;
+ scale_x ++;
+ }
+ p++;
+ x++;
+ count--;
+ }
+ if (done & 0x1) p++;
+ break;
+ }
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ }
+ else if ((bit_count == 16) || (bit_count == 24) || (bit_count == 32))
+ {
+ if (comp == 0) // no compression
+ {
+ position = offset;
+ if (scale_ratio == 1)
+ buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ else
+ buffer = malloc(row_size); // scale down is usually set because of memory issue, so read line by line
+ if (!buffer)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ if (scale_ratio == 1)
+ buffer_end = buffer + image_size;
+ else
+ buffer_end = buffer + row_size;
+
+ p = buffer;
+ if (scale_ratio == 1)
+ {
+ if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
+ }
+ else
+ {
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ }
+ if (bit_count == 16)
+ {
+ unsigned short tmp;
+
+ pix = surface;
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ for (x = 0; x < w; x++)
+ {
+ tmp = *((unsigned short *)(p));
+
+ r = (tmp >> 7) & 0xf8; r |= r >> 5;
+ g = (tmp >> 2) & 0xf8; g |= g >> 5;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ *pix = ARGB_JOIN(0xff, r, g, b);
+
+ p += 2 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (bit_count == 24)
+ {
+ pix = surface;
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ for (x = 0; x < w; x++)
+ {
+ b = p[0];
+ g = p[1];
+ r = p[2];
+ *pix = ARGB_JOIN(0xff, r, g, b);
+ p += 3 * scale_ratio;
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (bit_count == 32)
+ {
+ int none_zero_alpha = 0;
+ pix = surface;
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ for (x = 0; x < w; x++)
+ {
+ b = p[0];
+ g = p[1];
+ r = p[2];
+ a = p[3];
+ if (a) none_zero_alpha = 1;
+ if (!hasa) a = 0xff;
+ *pix = ARGB_JOIN(a, r, g, b);
+ p += 4 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ if (!none_zero_alpha)
+ {
+ ilp->alpha = 0;
+ if (hasa)
+ {
+ unsigned int *pixend = surface + (w * h);
+
+ for (pix = surface; pix < pixend; pix++)
+ A_VAL(pix) = 0xff;
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ else if (comp == 3) // bit field
+ {
+ if (!read_uint(map, fsize, &position, &rmask)) goto close_file;
+ if (!read_uint(map, fsize, &position, &gmask)) goto close_file;
+ if (!read_uint(map, fsize, &position, &bmask)) goto close_file;
+
+ position = offset;
+ if (scale_ratio == 1)
+ buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ else
+ buffer = malloc(row_size); // scale down is usually set because of memory issue, so read line by line
+
+ if (!buffer)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ if (scale_ratio == 1)
+ buffer_end = buffer + image_size;
+ else
+ buffer_end = buffer + row_size;
+
+ p = buffer;
+ if (scale_ratio == 1)
+ {
+ if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
+ }
+ else
+ {
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ }
+
+ if ((bit_count == 16) &&
+ (rmask == 0xf800) && (gmask == 0x07e0) && (bmask == 0x001f)
+ )
+ {
+ unsigned short tmp;
+
+ pix = surface;
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ for (x = 0; x < w; x++)
+ {
+ tmp = *((unsigned short *)(p));
+
+ r = (tmp >> 8) & 0xf8; r |= r >> 5;
+ g = (tmp >> 3) & 0xfc; g |= g >> 6;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ *pix = ARGB_JOIN(0xff, r, g, b);
+
+ p += 2 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if ((bit_count == 16) &&
+ (rmask == 0x7c00) && (gmask == 0x03e0) && (bmask == 0x001f)
+ )
+ {
+ unsigned short tmp;
+ pix = surface;
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ for (x = 0; x < w; x++)
+ {
+ tmp = *((unsigned short *)(p));
+
+ r = (tmp >> 7) & 0xf8; r |= r >> 5;
+ g = (tmp >> 2) & 0xf8; g |= g >> 5;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ *pix = ARGB_JOIN(0xff, r, g, b);
+ p += 2 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer_end, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (bit_count == 32)
+ {
+ pix = surface;
+ for (y = 0; y < h; y++)
+ {
+ if (!right_way_up) pix = surface + ((h - 1 - y) * w);
+ for (x = 0; x < w; x++)
+ {
+ b = p[0];
+ g = p[1];
+ r = p[2];
+ a = p[3];
+ if (!hasa) a = 0xff;
+ *pix = ARGB_JOIN(a, r, g, b);
+
+ p += 4 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ else if (comp == 4) // jpeg - only printer drivers
+ {
+ goto close_file;
+ }
+ else if (comp == 3) // png - only printer drivers
+ {
+ goto close_file;
+ }
+ else
+ goto close_file;
+ }
+ else
+ goto close_file;
+
+ if (buffer) free(buffer);
+ if (scale_surface) free(scale_surface);
+
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+
+ evas_cserve2_image_premul(ilp);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+
+ close_file:
+ if (buffer) free(buffer);
+ if (scale_surface) free(scale_surface);
+ if (map) eina_file_map_free(f, map);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "bmp",
+ evas_image_load_file_head_bmp,
+ evas_image_load_file_data_bmp
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@evas_image_loader_eet_cflags@ \
+@EINA_CFLAGS@
+
+
+if BUILD_LOADER_EET
+#if !EVAS_STATIC_BUILD_EET
+
+pkgdir = $(libdir)/evas/cserve2/loaders/eet/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_eet.c
+
+module_la_LIBADD = @EINA_LIBS@ @evas_image_loader_eet_libs@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_eet.la
+
+#libevas_loader_eet_la_SOURCES = evas_image_load_eet.c
+#libevas_loader_eet_la_LIBADD = @evas_image_loader_eet_libs@
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h" /* so that EAPI in Eet.h is correctly defined */
+#endif
+
+#include <Eet.h>
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+
+static Eina_Bool
+evas_image_load_file_head_eet(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
+{
+ int alpha, compression, quality, lossy;
+ unsigned int w, h;
+ Eet_File *ef;
+ int ok;
+ Eina_Bool res = EINA_FALSE;
+
+ if (!key)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ ef = eet_open((char *)file, EET_FILE_MODE_READ);
+ if (!ef)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+ ok = eet_data_image_header_read(ef, key,
+ &w, &h, &alpha, &compression, &quality, &lossy);
+ if (!ok)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ goto on_error;
+ }
+ if (IMG_TOO_BIG(w, h))
+ {
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+ if (alpha) ilp->alpha = 1;
+ ilp->w = w;
+ ilp->h = h;
+ res = EINA_TRUE;
+ *error = CSERVE2_NONE;
+
+ on_error:
+ eet_close(ef);
+ return res;
+}
+
+Eina_Bool
+evas_image_load_file_data_eet(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
+{
+ unsigned int w, h;
+ int alpha, compression, quality, lossy, ok;
+ Eet_File *ef;
+ DATA32 *body, *p, *end, *data;
+ DATA32 nas = 0;
+ Eina_Bool res = EINA_FALSE;
+
+ if (!key)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+ ef = eet_open(file, EET_FILE_MODE_READ);
+ if (!ef)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+ ok = eet_data_image_header_read(ef, key,
+ &w, &h, &alpha, &compression, &quality, &lossy);
+ if (IMG_TOO_BIG(w, h))
+ {
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+ if (!ok)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ goto on_error;
+ }
+ data = ilp->buffer;
+ if (!data)
+ {
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+ ok = eet_data_image_read_to_surface(ef, key, 0, 0,
+ data, w, h, w * 4,
+ &alpha, &compression, &quality, &lossy);
+ if (!ok)
+ {
+ *error = CSERVE2_GENERIC;
+ goto on_error;
+ }
+ if (alpha)
+ {
+ ilp->alpha = 1;
+
+ body = ilp->buffer;
+
+ end = body + (w * h);
+ for (p = body; p < end; p++)
+ {
+ DATA32 r, g, b, a;
+
+ a = A_VAL(p);
+ r = R_VAL(p);
+ g = G_VAL(p);
+ b = B_VAL(p);
+ if ((a == 0) || (a == 255)) nas++;
+ if (r > a) r = a;
+ if (g > a) g = a;
+ if (b > a) b = a;
+ *p = ARGB_JOIN(a, r, g, b);
+ }
+ if ((ALPHA_SPARSE_INV_FRACTION * nas) >= (w * h))
+ ilp->alpha_sparse = 1;
+ }
+ *error = CSERVE2_NONE;
+ res = EINA_TRUE;
+
+ on_error:
+ eet_close(ef);
+ return res;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "eet",
+ evas_image_load_file_head_eet,
+ evas_image_load_file_data_eet
+};
+
+static Eina_Bool
+module_init(void)
+{
+ eet_init();
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+ eet_shutdown();
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_ICO
+#if !EVAS_STATIC_BUILD_ICO
+
+pkgdir = $(libdir)/evas/cserve2/loaders/ico/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_ico.c
+
+module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_ico.la
+#libevas_loader_ico_la_SOURCES = evas_image_load_ico.c
+#libevas_loader_ico_la_LIBADD =
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+static Eina_Bool
+read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
+{
+ unsigned char b[2];
+
+ if (*position + 2 > length) return EINA_FALSE;
+ b[0] = map[(*position)++];
+ b[1] = map[(*position)++];
+ *ret = (b[1] << 8) | b[0];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
+{
+ unsigned char b[4];
+ unsigned int i;
+
+ if (*position + 4 > length) return EINA_FALSE;
+ for (i = 0; i < 4; i++)
+ b[i] = map[(*position)++];
+ *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
+{
+ if (*position + 1 > length) return EINA_FALSE;
+ *ret = map[(*position)++];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
+{
+ if (*position + size > length) return EINA_FALSE;
+ memcpy(buffer, map + *position, size);
+ *position += size;
+ return EINA_TRUE;
+}
+
+enum
+{
+ SMALLEST,
+ BIGGEST,
+ SMALLER,
+ BIGGER
+};
+
+enum
+{
+ ICON = 1,
+ CURSOR = 2
+};
+
+static Eina_Bool
+evas_image_load_file_head_ico(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
+{
+ Eina_File *f;
+ void *map = NULL;
+ size_t position = 0;
+ unsigned short word;
+ unsigned char byte;
+ int wanted_w = 0, wanted_h = 0, w, h, cols, i, planes = 0,
+ bpp = 0, pdelta, search = -1, have_choice = 0,
+ hasa = 1;
+ unsigned int bmoffset, bmsize, fsize;
+ unsigned short reserved, type, count;
+ struct {
+ int pdelta;
+ int w, h;
+ int cols;
+ int bpp, planes;
+ int hot_x, hot_y;
+ unsigned int bmoffset, bmsize;
+ } chosen = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ f = eina_file_open(file, EINA_FALSE);
+ if (!f)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ fsize = eina_file_size_get(f);
+ if (fsize < (6 + 16 + 40)) goto close_file;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map) goto close_file;
+
+ // key:
+ // NULL == highest res
+ // biggest == highest res
+ // smallest == lowest res
+ //
+ // smaller == next size SMALLER than load opts WxH (if possible)
+ // bigger == next size BIGGER than load opts WxH (if possible)
+ // more ?
+
+ search = BIGGEST;
+ if ((ilp->opts.w > 0) && (ilp->opts.h > 0))
+ {
+ wanted_w = ilp->opts.w;
+ wanted_h = ilp->opts.h;
+ search = SMALLER;
+ }
+
+ if (!read_ushort(map, fsize, &position, &reserved)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &type)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &count)) goto close_file;
+ if (!((reserved == 0) &&
+ ((type == ICON) || (type == CURSOR)) && (count > 0)))
+ goto close_file;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+ if (key)
+ {
+ if (!strcmp(key, "biggest"))
+ {
+ wanted_w = 0;
+ wanted_h = 0;
+ search = BIGGEST;
+ chosen.pdelta = 0;
+ }
+ else if (!strcmp(key, "smallest"))
+ {
+ wanted_w = 1;
+ wanted_h = 1;
+ search = SMALLEST;
+ chosen.pdelta = 0x7fffffff;
+ }
+ else if (!strcmp(key, "smaller"))
+ {
+ chosen.pdelta = 0x7fffffff;
+ search = SMALLER;
+ }
+ else if (!strcmp(key, "bigger"))
+ {
+ chosen.pdelta = 0x7fffffff;
+ search = BIGGER;
+ }
+ }
+ for (i = 0; i < count; i++)
+ {
+ unsigned char tw = 0, th = 0, tcols = 0;
+ if (!read_uchar(map, fsize, &position, &tw)) goto close_file;
+ w = tw;
+ if (w <= 0) w = 256;
+ if (!read_uchar(map, fsize, &position, &th)) goto close_file;
+ h = th;
+ if (h <= 0) h = 256;
+ if (!read_uchar(map, fsize, &position, &tcols)) goto close_file;
+ cols = tcols;
+ if (cols <= 0) cols = 256;
+ if (!read_uchar(map, fsize, &position, &byte)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file;
+ if (type == CURSOR) planes = word;
+ //else hot_x = word;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file;
+ if (type == CURSOR) bpp = word;
+ //else hot_y = word;
+ if (!read_uint(map, fsize, &position, &bmsize)) goto close_file;
+ if (!read_uint(map, fsize, &position, &bmoffset)) goto close_file;
+ if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize)) goto close_file;
+ if (search == BIGGEST)
+ {
+ pdelta = w * h;
+ if ((!have_choice) ||
+ ((pdelta >= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else
+ {
+ if (search == SMALLEST)
+ {
+ pdelta = w * h;
+ if ((!have_choice) ||
+ ((pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else if (search == SMALLER)
+ {
+ pdelta = (wanted_w * wanted_h) - (w * h);
+ if ((!have_choice) ||
+ ((w <= wanted_w) && (h <= wanted_h) &&
+ (pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ if (pdelta < 0) pdelta = 0x7fffffff;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else if (search == BIGGER)
+ {
+ pdelta = (w * h) - (wanted_w * wanted_h);
+ if ((!have_choice) ||
+ ((w >= wanted_w) && (h >= wanted_h) &&
+ (pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ if (pdelta < 0) pdelta = 0x7fffffff;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ }
+ }
+ if (chosen.bmoffset == 0) goto close_file;
+ position = chosen.bmoffset;
+
+ w = chosen.w;
+ h = chosen.h;
+ if ((w > 256) || (h > 256)) goto close_file;
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ {
+ if (IMG_TOO_BIG(w, h))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+
+ ilp->w = w;
+ ilp->h = h;
+ if (hasa) ilp->alpha = 1;
+
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+
+ close_file:
+ if (map) eina_file_map_free(f, map);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_ico(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
+{
+ Eina_File *f;
+ void *map = NULL;
+ size_t position = 0;
+ unsigned short word;
+ unsigned char byte;
+ unsigned int dword;
+ int wanted_w = 0, wanted_h = 0, w, h, cols, i, planes = 0,
+ bpp = 0, pdelta, search = -1, have_choice = 0,
+ stride, pstride, j, right_way_up = 0, diff_size = 0, cols2;
+ unsigned int bmoffset, bmsize, bitcount, fsize,
+ *pal, *surface, *pix, none_zero_alpha = 0;
+ unsigned short reserved, type, count;
+ unsigned char *maskbuf, *pixbuf, *p;
+ struct {
+ int pdelta;
+ int w, h;
+ int cols;
+ int bpp, planes;
+ int hot_x, hot_y;
+ unsigned int bmoffset, bmsize;
+ } chosen = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ f = eina_file_open(file, EINA_FALSE);
+ if (!f)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ fsize = eina_file_size_get(f);
+ if (fsize < (6 + 16 + 40)) goto close_file;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map) goto close_file;
+
+ // key:
+ // NULL == highest res
+ // biggest == highest res
+ // smallest == lowest res
+ //
+ // smaller == next size SMALLER than load opts WxH (if possible)
+ // bigger == next size BIGGER than load opts WxH (if possible)
+ // more ?
+
+ search = BIGGEST;
+ if ((ilp->opts.w > 0) && (ilp->opts.h > 0))
+ {
+ wanted_w = ilp->opts.w;
+ wanted_h = ilp->opts.h;
+ search = SMALLER;
+ }
+
+ if (!read_ushort(map, fsize, &position, &reserved)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &type)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &count)) goto close_file;
+ if (!((reserved == 0) &&
+ ((type == ICON) || (type == CURSOR)) && (count > 0)))
+ goto close_file;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+ if (key)
+ {
+ if (!strcmp(key, "biggest"))
+ {
+ wanted_w = 0;
+ wanted_h = 0;
+ search = BIGGEST;
+ chosen.pdelta = 0;
+ }
+ else if (!strcmp(key, "smallest"))
+ {
+ wanted_w = 1;
+ wanted_h = 1;
+ search = SMALLEST;
+ chosen.pdelta = 0x7fffffff;
+ }
+ else if (!strcmp(key, "smaller"))
+ {
+ chosen.pdelta = 0x7fffffff;
+ search = SMALLER;
+ }
+ else if (!strcmp(key, "bigger"))
+ {
+ chosen.pdelta = 0x7fffffff;
+ search = BIGGER;
+ }
+ }
+ for (i = 0; i < count; i++)
+ {
+ unsigned char tw = 0, th = 0, tcols = 0;
+ if (!read_uchar(map, fsize, &position, &tw)) goto close_file;
+ w = tw;
+ if (w <= 0) w = 256;
+ if (!read_uchar(map, fsize, &position, &th)) goto close_file;
+ h = th;
+ if (h <= 0) h = 256;
+ if (!read_uchar(map, fsize, &position, &tcols)) goto close_file;
+ cols = tcols;
+ if (cols <= 0) cols = 256;
+ if (!read_uchar(map, fsize, &position, &byte)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file;
+ if (type == 1) planes = word;
+ //else hot_x = word;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file;
+ if (type == 1) bpp = word;
+ //else hot_y = word;
+ if (!read_uint(map, fsize, &position, &bmsize)) goto close_file;
+ if (!read_uint(map, fsize, &position, &bmoffset)) goto close_file;
+ if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize)) goto close_file;
+ if (search == BIGGEST)
+ {
+ pdelta = w * h;
+ if ((!have_choice) ||
+ ((pdelta >= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else
+ {
+ if (search == SMALLEST)
+ {
+ pdelta = w * h;
+ if ((!have_choice) ||
+ ((pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else if (search == SMALLER)
+ {
+ pdelta = (wanted_w * wanted_h) - (w * h);
+ if ((!have_choice) ||
+ ((w <= wanted_w) && (h <= wanted_h) &&
+ (pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ if (pdelta < 0) pdelta = 0x7fffffff;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else if (search == BIGGER)
+ {
+ pdelta = (w * h) - (wanted_w * wanted_h);
+ if ((!have_choice) ||
+ ((w >= wanted_w) && (h >= wanted_h) &&
+ (pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ if (pdelta < 0) pdelta = 0x7fffffff;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ }
+ }
+ if (chosen.bmoffset == 0) goto close_file;
+ position = chosen.bmoffset;
+
+ w = chosen.w;
+ h = chosen.h;
+ cols = chosen.cols;
+ bpp = chosen.bpp;
+ // changed since we loaded header?
+ if (((int)ilp->w != w) || ((int)ilp->h != h)) goto close_file;
+
+ // read bmp header time... let's do some checking
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // headersize - dont care
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // width
+ if (dword > 0)
+ {
+ if ((int)dword != w)
+ {
+ w = dword;
+ diff_size = 1;
+ }
+ }
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // height
+ if (dword > 0)
+ {
+ if ((int)dword != (h * 2))
+ {
+ h = dword / 2;
+ diff_size = 1;
+ }
+ }
+ if (diff_size)
+ {
+ ERR("Broken ICO file: %s - "
+ " Reporting size of %ix%i in index, but bitmap is %ix%i. "
+ " May be expanded or cropped.",
+ file, ilp->w, ilp->h, w, h);
+ }
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file; // planes
+ //planes2 = word;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file; // bitcount
+ bitcount = word;
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // compression
+ //compression = dword;
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // imagesize
+ //imagesize = dword;
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // z pixels per m
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // y pizels per m
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // colors used
+ //colorsused = dword;
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // colors important
+ //colorsimportant = dword;
+
+ surface = ilp->buffer;
+ if (!surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ memset(surface, 0, ilp->w * ilp->h * 4);
+
+ if (!((bitcount == 1) || (bitcount == 4) || (bitcount == 8) ||
+ (bitcount == 24) || (bitcount == 32)))
+ goto close_file;
+ if (bitcount <= 8)
+ {
+ cols2 = 1 << bitcount;
+ if (cols == 0) cols = cols2;
+ if (cols > cols2) cols = cols2;
+ if (cols > 256) cols = 256;
+ }
+ else
+ cols = 0;
+ if (bitcount > 8) cols = 0;
+
+ pal = alloca(256 * 4);
+ for (i = 0; i < cols; i++)
+ {
+ unsigned char a, r, g, b;
+
+ if (!read_uchar(map, fsize, &position, &b)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &g)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &r)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &a)) goto close_file;
+ a = 0xff;
+ pal[i] = ARGB_JOIN(a, r, g, b);
+ }
+ stride = ((w + 31) / 32);
+ maskbuf = alloca(stride * h);
+ pixbuf = alloca(stride * 32 * 4); // more than enough
+ if (bitcount == 1)
+ {
+ pstride = stride * 4;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * ilp->w);
+ if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= (int)ilp->h) continue;
+ for (j = 0; j < w; j++)
+ {
+ if (j >= (int)ilp->w) break;
+ if ((j & 0x7) == 0x0)
+ {
+ *pix = pal[*p >> 7];
+ }
+ else if ((j & 0x7) == 0x1)
+ {
+ *pix = pal[(*p >> 6) & 0x1];
+ }
+ else if ((j & 0x7) == 0x2)
+ {
+ *pix = pal[(*p >> 5) & 0x1];
+ }
+ else if ((j & 0x7) == 0x3)
+ {
+ *pix = pal[(*p >> 4) & 0x1];
+ }
+ else if ((j & 0x7) == 0x4)
+ {
+ *pix = pal[(*p >> 3) & 0x1];
+ }
+ else if ((j & 0x7) == 0x5)
+ {
+ *pix = pal[(*p >> 2) & 0x1];
+ }
+ else if ((j & 0x7) == 0x6)
+ {
+ *pix = pal[(*p >> 1) & 0x1];
+ }
+ else
+ {
+ *pix = pal[*p & 0x1];
+ p++;
+ }
+ pix++;
+ }
+ }
+ }
+ else if (bitcount == 4)
+ {
+ pstride = ((w + 7) / 8) * 4;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * ilp->w);
+ if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= (int)ilp->h) continue;
+ for (j = 0; j < w; j++)
+ {
+ if (j >= (int)ilp->w) break;
+ if ((j & 0x1) == 0x1)
+ {
+ *pix = pal[*p & 0x0f];
+ p++;
+ }
+ else
+ {
+ *pix = pal[*p >> 4];
+ }
+ pix++;
+ }
+ }
+ }
+ else if (bitcount == 8)
+ {
+ pstride = ((w + 3) / 4) * 4;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * ilp->w);
+ if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= (int)ilp->h) continue;
+ for (j = 0; j < w; j++)
+ {
+ if (j >= (int)ilp->w) break;
+ *pix = pal[*p];
+ p++;
+ pix++;
+ }
+ }
+ }
+ else if (bitcount == 24)
+ {
+ pstride = w * 3;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * ilp->w);
+ if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= (int)ilp->h) continue;
+ for (j = 0; j < w; j++)
+ {
+ unsigned char a, r, g, b;
+
+ if (j >= (int)ilp->w) break;
+ b = p[0];
+ g = p[1];
+ r = p[2];
+ p += 3;
+ a = 0xff;
+ *pix = ARGB_JOIN(a, r, g, b);
+ pix++;
+ }
+ }
+ }
+ else if (bitcount == 32)
+ {
+ pstride = w * 4;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * ilp->w);
+ if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= (int)ilp->h) continue;
+ for (j = 0; j < w; j++)
+ {
+ unsigned char a, r, g, b;
+
+ if (j >= (int)ilp->w) break;
+ b = p[0];
+ g = p[1];
+ r = p[2];
+ a = p[3];
+ p += 4;
+ if (a) none_zero_alpha = 1;
+ *pix = ARGB_JOIN(a, r, g, b);
+ pix++;
+ }
+ }
+ }
+ if (!none_zero_alpha)
+ {
+ if (!read_mem(map, fsize, &position, maskbuf, stride * 4 * h)) goto close_file;
+ // apply mask
+ pix = surface;
+ for (i = 0; i < h; i++)
+ {
+ unsigned char *m;
+
+ pix = surface + (i * ilp->w);
+ if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
+ m = maskbuf + (stride * i * 4);
+ if (i >= (int)ilp->h) continue;
+ for (j = 0; j < w; j++)
+ {
+ if (j >= (int)ilp->w) break;
+ if (*m & (1 << (7 - (j & 0x7))))
+ A_VAL(pix) = 0x00;
+ else
+ A_VAL(pix) = 0xff;
+ if ((j & 0x7) == 0x7) m++;
+ pix++;
+ }
+ }
+ }
+
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+
+ evas_cserve2_image_premul(ilp);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+
+ close_file:
+ if (map) eina_file_map_free(f, map);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "ico",
+ evas_image_load_file_head_ico,
+ evas_image_load_file_data_ico
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@evas_image_loader_jpeg_cflags@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_JPEG
+#if !EVAS_STATIC_BUILD_JPEG
+
+pkgdir = $(libdir)/evas/cserve2/loaders/jpeg/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_jpeg.c
+
+module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@ @evas_image_loader_jpeg_libs@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_jpeg.la
+#libevas_loader_jpeg_la_SOURCES = evas_image_load_jpeg.c
+#libevas_loader_jpeg_la_LIBADD = @evas_image_loader_jpeg_libs@
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include <setjmp.h>
+#include <jpeglib.h>
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+typedef struct _JPEG_error_mgr *emptr;
+struct _JPEG_error_mgr
+{
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+};
+
+static void _JPEGFatalErrorHandler(j_common_ptr cinfo);
+static void _JPEGErrorHandler(j_common_ptr cinfo);
+static void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level);
+
+static void
+_JPEGFatalErrorHandler(j_common_ptr cinfo)
+{
+ emptr errmgr;
+
+ errmgr = (emptr) cinfo->err;
+ /* cinfo->err->output_message(cinfo);*/
+ longjmp(errmgr->setjmp_buffer, 1);
+ return;
+}
+
+static void
+_JPEGErrorHandler(j_common_ptr cinfo __UNUSED__)
+{
+/* emptr errmgr; */
+
+/* errmgr = (emptr) cinfo->err; */
+ /* cinfo->err->output_message(cinfo);*/
+ /* longjmp(errmgr->setjmp_buffer, 1);*/
+ return;
+}
+
+static void
+_JPEGErrorHandler2(j_common_ptr cinfo __UNUSED__, int msg_level __UNUSED__)
+{
+/* emptr errmgr; */
+
+/* errmgr = (emptr) cinfo->err; */
+ /* cinfo->err->output_message(cinfo);*/
+ /* longjmp(errmgr->setjmp_buffer, 1);*/
+ return;
+}
+
+struct jpeg_membuf_src
+{
+ struct jpeg_source_mgr pub;
+
+ const unsigned char *buf;
+ size_t len;
+ struct jpeg_membuf_src *self;
+};
+
+static void
+_evas_jpeg_membuf_src_init(j_decompress_ptr cinfo __UNUSED__)
+{
+}
+
+static boolean
+_evas_jpeg_membuf_src_fill(j_decompress_ptr cinfo)
+{
+ static const JOCTET jpeg_eoi[2] = { 0xFF, JPEG_EOI };
+ struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
+
+ src->pub.bytes_in_buffer = sizeof(jpeg_eoi);
+ src->pub.next_input_byte = jpeg_eoi;
+
+ return TRUE;
+}
+
+static void
+_evas_jpeg_membuf_src_skip(j_decompress_ptr cinfo,
+ long num_bytes)
+{
+ struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
+
+ if ((((long)src->pub.bytes_in_buffer - (long)src->len) > num_bytes) ||
+ ((long)src->pub.bytes_in_buffer < num_bytes))
+ {
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo));
+ return;
+ }
+ src->pub.bytes_in_buffer -= num_bytes;
+ src->pub.next_input_byte += num_bytes;
+}
+
+static void
+_evas_jpeg_membuf_src_term(j_decompress_ptr cinfo)
+{
+ struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
+ if (!src) return;
+ free(src);
+ cinfo->src = NULL;
+}
+
+static int
+_evas_jpeg_membuf_src(j_decompress_ptr cinfo,
+ void *map, size_t length)
+{
+ struct jpeg_membuf_src *src;
+
+ src = calloc(1, sizeof(*src));
+ if (!src)
+ return -1;
+
+ src->self = src;
+
+ cinfo->src = &src->pub;
+ src->buf = map;
+ src->len = length;
+ src->pub.init_source = _evas_jpeg_membuf_src_init;
+ src->pub.fill_input_buffer = _evas_jpeg_membuf_src_fill;
+ src->pub.skip_input_data = _evas_jpeg_membuf_src_skip;
+ src->pub.resync_to_restart = jpeg_resync_to_restart;
+ src->pub.term_source = _evas_jpeg_membuf_src_term;
+ src->pub.bytes_in_buffer = src->len;
+ src->pub.next_input_byte = src->buf;
+
+ return 0;
+}
+
+/*! Magic number for EXIF header & App1*/
+static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
+static const unsigned char App1[] = {0xff, 0xe1};
+typedef enum {
+ EXIF_BYTE_ALIGN_II,
+ EXIF_BYTE_ALIGN_MM
+} ExifByteAlign;
+
+static int
+_get_orientation(void *map, size_t length)
+{
+ char *buf;
+ char orientation[2];
+ ExifByteAlign byte_align;
+ unsigned int num_directory = 0;
+ unsigned int i, j;
+ int direction;
+
+ /* open file and get 22 byte frome file */
+ if (!map) return 0;
+ /* 1. read 22byte */
+ if (length < 22) return 0;
+ buf = (char *)map;
+
+ /* 2. check 2,3 bypte with APP1(0xFFE1) */
+ if (memcmp(buf + 2, App1, sizeof (App1))) return 0;
+
+ /* 3. check 6~11bype with Exif Header (0x45786966 0000) */
+ if (memcmp(buf + 6, ExifHeader, sizeof (ExifHeader))) return 0;
+
+ /* 4. get 12&13 byte get info of "II(0x4949)" or "MM(0x4d4d)" */
+ /* 5. get [20]&[21] get directory entry # */
+ if (!strncmp(buf + 12, "MM", 2))
+ {
+ byte_align = EXIF_BYTE_ALIGN_MM;
+ num_directory = ((*(buf + 20) << 8) + *(buf + 21));
+ orientation[0] = 0x01;
+ orientation[1] = 0x12;
+ }
+ else if (!strncmp(buf + 12, "II", 2))
+ {
+ byte_align = EXIF_BYTE_ALIGN_II;
+ num_directory = ((*(buf + 21) << 8) + *(buf + 20));
+ orientation[0] = 0x12;
+ orientation[1] = 0x01;
+ }
+ else return 0;
+
+ buf = map + 22;
+
+ if (length < (12 * num_directory + 22)) return 0;
+
+ j = 0;
+
+ for (i = 0; i < num_directory; i++ )
+ {
+ if (!strncmp(buf + j, orientation, 2))
+ {
+ /*get orientation tag */
+ if (byte_align == EXIF_BYTE_ALIGN_MM)
+ direction = *(buf+ j + 11);
+ else direction = *(buf+ j + 8);
+ switch (direction)
+ {
+ case 3:
+ case 4:
+ return 180;
+ case 6:
+ case 7:
+ return 90;
+ case 5:
+ case 8:
+ return 270;
+ default:
+ return 0;
+ }
+ }
+ else
+ j = j + 12;
+ }
+ return 0;
+}
+
+static Eina_Bool
+evas_image_load_file_head_jpeg_internal(Evas_Img_Load_Params *ilp,
+ void *map, size_t length,
+ int *error)
+{
+ unsigned int w, h, scalew, scaleh;
+ struct jpeg_decompress_struct cinfo;
+ struct _JPEG_error_mgr jerr;
+
+ /* for rotation decoding */
+ int degree = 0;
+ Eina_Bool change_wh = EINA_FALSE;
+ unsigned int load_opts_w = 0, load_opts_h = 0;
+
+ cinfo.err = jpeg_std_error(&(jerr.pub));
+ jerr.pub.error_exit = _JPEGFatalErrorHandler;
+ jerr.pub.emit_message = _JPEGErrorHandler2;
+ jerr.pub.output_message = _JPEGErrorHandler;
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ if (cinfo.saw_JFIF_marker)
+ *error = CSERVE2_CORRUPT_FILE;
+ else
+ *error = CSERVE2_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ degree = 0;
+ change_wh = EINA_FALSE;
+ jpeg_create_decompress(&cinfo);
+
+ if (_evas_jpeg_membuf_src(&cinfo, map, length))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.do_fancy_upsampling = FALSE;
+ cinfo.do_block_smoothing = FALSE;
+ cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss)
+ cinfo.dither_mode = JDITHER_ORDERED;
+ jpeg_start_decompress(&cinfo);
+
+ /* rotation decoding */
+ if (ilp->opts.orientation)
+ {
+ degree = _get_orientation(map, length);
+ if (degree != 0)
+ {
+ ilp->degree = degree;
+ ilp->rotated = EINA_TRUE;
+
+ if (degree == 90 || degree == 270)
+ change_wh = EINA_TRUE;
+ }
+
+ }
+
+ /* head decoding */
+ w = cinfo.output_width;
+ h = cinfo.output_height;
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ (IMG_TOO_BIG(w, h)))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ if (IMG_TOO_BIG(w, h))
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = CSERVE2_GENERIC;
+ return EINA_FALSE;
+ }
+ if (ilp->opts.scale_down_by > 1)
+ {
+ w /= ilp->opts.scale_down_by;
+ h /= ilp->opts.scale_down_by;
+ }
+ else if (ilp->opts.dpi > 0.0)
+ {
+ w = (w * ilp->opts.dpi) / 90.0;
+ h = (h * ilp->opts.dpi) / 90.0;
+ }
+ else if ((ilp->opts.w > 0) && (ilp->opts.h > 0))
+ {
+ unsigned int w2 = w, h2 = h;
+ /* user set load_opts' w,h on the assumption
+ that image already rotated according to it's orientation info */
+ if (change_wh)
+ {
+ load_opts_w = ilp->opts.w;
+ load_opts_h = ilp->opts.h;
+ ilp->opts.w = load_opts_h;
+ ilp->opts.h = load_opts_w;
+ }
+
+ if (ilp->opts.w > 0)
+ {
+ w2 = ilp->opts.w;
+ h2 = (ilp->opts.w * h) / w;
+ if ((ilp->opts.h > 0) && (h2 > ilp->opts.h))
+ {
+ unsigned int w3;
+ h2 = ilp->opts.h;
+ w3 = (ilp->opts.h * w) / h;
+ if (w3 > w2)
+ w2 = w3;
+ }
+ }
+ else if (ilp->opts.h > 0)
+ {
+ h2 = ilp->opts.h;
+ w2 = (ilp->opts.h * w) / h;
+ }
+ w = w2;
+ h = h2;
+ if (change_wh)
+ {
+ ilp->opts.w = load_opts_w;
+ ilp->opts.h = load_opts_h;
+ }
+ }
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ if ((w != cinfo.output_width) || (h != cinfo.output_height))
+ {
+ scalew = cinfo.output_width / w;
+ scaleh = cinfo.output_height / h;
+
+ ilp->scale = scalew;
+ if (scaleh < scalew) ilp->scale = scaleh;
+
+ if (ilp->scale > 8) ilp->scale = 8;
+ else if (ilp->scale < 1) ilp->scale = 1;
+
+ if (ilp->scale == 3) ilp->scale = 2;
+ else if (ilp->scale == 5) ilp->scale = 4;
+ else if (ilp->scale == 6) ilp->scale = 4;
+ else if (ilp->scale == 7) ilp->scale = 4;
+ }
+
+ if (ilp->scale > 1)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ jpeg_create_decompress(&cinfo);
+
+ if (_evas_jpeg_membuf_src(&cinfo, map, length))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.do_fancy_upsampling = FALSE;
+ cinfo.do_block_smoothing = FALSE;
+ cinfo.scale_num = 1;
+ cinfo.scale_denom = ilp->scale;
+ jpeg_calc_output_dimensions(&(cinfo));
+ jpeg_start_decompress(&cinfo);
+ }
+
+ ilp->w = cinfo.output_width;
+ ilp->h = cinfo.output_height;
+
+ // be nice and clip region to image. if its totally outside, fail load
+ if ((ilp->opts.rw > 0) && (ilp->opts.rh > 0))
+ {
+ unsigned int load_region_x = 0, load_region_y = 0;
+ unsigned int load_region_w = 0, load_region_h = 0;
+ if (ilp->rotated)
+ {
+ load_region_x = ilp->opts.rx;
+ load_region_y = ilp->opts.ry;
+ load_region_w = ilp->opts.rw;
+ load_region_h = ilp->opts.rh;
+
+ switch (degree)
+ {
+ case 90:
+ ilp->opts.rx = load_region_y;
+ ilp->opts.ry = h - (load_region_x + load_region_w);
+ ilp->opts.rw = load_region_h;
+ ilp->opts.rh = load_region_w;
+ break;
+ case 180:
+ ilp->opts.rx = w - (load_region_x+ load_region_w);
+ ilp->opts.ry = h - (load_region_y + load_region_h);
+
+ break;
+ case 270:
+ ilp->opts.rx = w - (load_region_y + load_region_h);
+ ilp->opts.ry = load_region_x;
+ ilp->opts.rw = load_region_h;
+ ilp->opts.rh = load_region_w;
+ break;
+ default:
+ break;
+ }
+
+ }
+ RECTS_CLIP_TO_RECT(ilp->opts.rx, ilp->opts.ry,
+ ilp->opts.rw, ilp->opts.rh,
+ 0, 0, ilp->w, ilp->h);
+ if ((ilp->opts.rw <= 0) || (ilp->opts.rh <= 0))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_GENERIC;
+ return EINA_FALSE;
+ }
+ ilp->w = ilp->opts.rw;
+ ilp->h = ilp->opts.rh;
+ if (ilp->rotated)
+ {
+ ilp->opts.rx = load_region_x;
+ ilp->opts.ry = load_region_y;
+ ilp->opts.rw = load_region_w;
+ ilp->opts.rh = load_region_h;
+ }
+ }
+/* end head decoding */
+
+ if (change_wh)
+ {
+ unsigned int tmp;
+ tmp = ilp->w;
+ ilp->w = ilp->h;
+ ilp->h = tmp;
+ }
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_NONE;
+ return EINA_TRUE;
+}
+
+/*
+static double
+get_time(void)
+{
+ struct timeval timev;
+
+ gettimeofday(&timev, NULL);
+ return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
+}
+*/
+
+static Eina_Bool
+evas_image_load_file_data_jpeg_internal(Evas_Img_Load_Params *ilp,
+ void *map, size_t size,
+ int *error)
+{
+ unsigned int w, h;
+ struct jpeg_decompress_struct cinfo;
+ struct _JPEG_error_mgr jerr;
+ DATA8 *ptr, *line[16], *data;
+ DATA32 *ptr2, *ptr_rotate = NULL;
+ unsigned int x, y, l, i, scans;
+ int region = 0;
+ /* rotation setting */
+ unsigned int tmp;
+ unsigned int load_region_x = 0, load_region_y = 0;
+ unsigned int load_region_w = 0, load_region_h = 0;
+ volatile int degree = 0;
+ volatile Eina_Bool change_wh = EINA_FALSE;
+ Eina_Bool line_done = EINA_FALSE;
+
+ if (ilp->rotated)
+ {
+ degree = ilp->degree;
+ if (degree == 90 || degree == 270)
+ change_wh = EINA_TRUE;
+ }
+
+ cinfo.err = jpeg_std_error(&(jerr.pub));
+ jerr.pub.error_exit = _JPEGFatalErrorHandler;
+ jerr.pub.emit_message = _JPEGErrorHandler2;
+ jerr.pub.output_message = _JPEGErrorHandler;
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ jpeg_create_decompress(&cinfo);
+
+ if (_evas_jpeg_membuf_src(&cinfo, map, size))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ return 0;
+ }
+
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.do_fancy_upsampling = FALSE;
+ cinfo.do_block_smoothing = FALSE;
+ cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss)
+ cinfo.dither_mode = JDITHER_ORDERED;
+
+ if (ilp->scale > 1)
+ {
+ cinfo.scale_num = 1;
+ cinfo.scale_denom = ilp->scale;
+ }
+
+ /* Colorspace conversion options */
+ /* libjpeg can do the following conversions: */
+ /* GRAYSCLAE => RGB YCbCr => RGB and YCCK => CMYK */
+ switch (cinfo.jpeg_color_space)
+ {
+ case JCS_UNKNOWN:
+ break;
+ case JCS_GRAYSCALE:
+ case JCS_RGB:
+ case JCS_YCbCr:
+ cinfo.out_color_space = JCS_RGB;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo.out_color_space = JCS_CMYK;
+ break;
+ default:
+ /* unhandled format, do something */
+ break;
+ }
+
+/* head decoding */
+ jpeg_calc_output_dimensions(&(cinfo));
+ jpeg_start_decompress(&cinfo);
+
+ w = cinfo.output_width;
+ h = cinfo.output_height;
+
+ if (change_wh)
+ {
+ tmp = ilp->w;
+ ilp->w = ilp->h;
+ ilp->h = tmp;
+ }
+
+ if ((ilp->opts.rw > 0) && (ilp->opts.rh > 0))
+ {
+ region = 1;
+
+ if (ilp->rotated)
+ {
+ load_region_x = ilp->opts.rx;
+ load_region_y = ilp->opts.ry;
+ load_region_w = ilp->opts.rw;
+ load_region_h = ilp->opts.rh;
+
+ switch (degree)
+ {
+ case 90:
+ ilp->opts.rx = load_region_y;
+ ilp->opts.ry = h - (load_region_x + load_region_w);
+ ilp->opts.rw = load_region_h;
+ ilp->opts.rh = load_region_w;
+ break;
+ case 180:
+ ilp->opts.rx = w - (load_region_x+ load_region_w);
+ ilp->opts.ry = h - (load_region_y + load_region_h);
+
+ break;
+ case 270:
+ ilp->opts.rx = w - (load_region_y + load_region_h);
+ ilp->opts.ry = load_region_x;
+ ilp->opts.rw = load_region_h;
+ ilp->opts.rh = load_region_w;
+ break;
+ default:
+ break;
+ }
+
+ }
+#ifdef BUILD_LOADER_JPEG_REGION
+ cinfo.region_x = ilp->opts.rx;
+ cinfo.region_y = ilp->opts.ry;
+ cinfo.region_w = ilp->opts.rw;
+ cinfo.region_h = ilp->opts.rh;
+#endif
+ }
+ /* what to do about this? We'll check for this kind of races on loaders
+ * or cache invalidation due to file modification should always be
+ * detected by the server? */
+
+ if ((!region) && ((w != ilp->w) || (h != ilp->h)))
+ {
+ // race condition, the file could have change from when we call header
+ // this test will not solve the problem with region code.
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_GENERIC;
+ return EINA_FALSE;
+ }
+
+ if ((region) &&
+ ((ilp->w != ilp->opts.rw) || (ilp->h != ilp->opts.rh)))
+ {
+ ilp->w = ilp->opts.rw;
+ ilp->h = ilp->opts.rh;
+ }
+
+ if (!(((cinfo.out_color_space == JCS_RGB) &&
+ ((cinfo.output_components == 3) || (cinfo.output_components == 1))) ||
+ ((cinfo.out_color_space == JCS_CMYK) && (cinfo.output_components == 4))))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+/* end head decoding */
+/* data decoding */
+ if (cinfo.rec_outbuf_height > 16)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+ data = alloca(w * 16 * cinfo.output_components);
+ if ((ilp->rotated) && change_wh)
+ {
+ ptr2 = malloc(ilp->w * ilp->h * sizeof(DATA32));
+ ptr_rotate = ptr2;
+ }
+ else
+ ptr2 = ilp->buffer;;
+
+ if (!ptr2)
+ {
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ /* We handle first CMYK (4 components) */
+ if (cinfo.output_components == 4)
+ {
+ // FIXME: handle region
+ for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
+ line[i] = data + (i * w * 4);
+ for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+ {
+ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+ scans = cinfo.rec_outbuf_height;
+ if ((h - l) < scans) scans = h - l;
+ ptr = data;
+ if (!region)
+ {
+ for (y = 0; y < scans; y++)
+ {
+ if (cinfo.saw_Adobe_marker)
+ {
+ for (x = 0; x < w; x++)
+ {
+ /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */
+ /* that is C is replaces by 255 - C, etc...*/
+ /* See the comment below for the computation of RGB values from CMYK ones. */
+ *ptr2 =
+ (0xff000000) |
+ ((ptr[0] * ptr[3] / 255) << 16) |
+ ((ptr[1] * ptr[3] / 255) << 8) |
+ ((ptr[2] * ptr[3] / 255));
+ ptr += 4;
+ ptr2++;
+ }
+ }
+ else
+ {
+ for (x = 0; x < w; x++)
+ {
+ /* Conversion from CMYK to RGB is done in 2 steps: */
+ /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */
+ /* after computation, if C, M, Y and K are between 0 and 1, we have: */
+ /* R = (1 - C) * (1 - K) * 255 */
+ /* G = (1 - M) * (1 - K) * 255 */
+ /* B = (1 - Y) * (1 - K) * 255 */
+ /* libjpeg stores CMYK values between 0 and 255, */
+ /* so we replace C by C * 255 / 255, etc... and we obtain: */
+ /* R = (255 - C) * (255 - K) / 255 */
+ /* G = (255 - M) * (255 - K) / 255 */
+ /* B = (255 - Y) * (255 - K) / 255 */
+ /* with C, M, Y and K between 0 and 255. */
+ *ptr2 =
+ (0xff000000) |
+ (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
+ (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
+ (((255 - ptr[2]) * (255 - ptr[3]) / 255));
+ ptr += 4;
+ ptr2++;
+ }
+ }
+ }
+ }
+ else
+ {
+ // if line # > region last line, break
+ if (l >= (ilp->opts.ry + ilp->opts.rh))
+ {
+ line_done = EINA_TRUE;
+ /* if rotation flag is set , we have to rotate image */
+ goto done;
+ /*jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = NONE;
+ return EINA_FALSE;*/
+ }
+ // els if scan block intersects region start or later
+ else if ((l + scans) >
+ (ilp->opts.ry))
+ {
+ for (y = 0; y < scans; y++)
+ {
+ if (((y + l) >= ilp->opts.ry) &&
+ ((y + l) < (ilp->opts.ry + ilp->opts.rh)))
+ {
+ ptr += ilp->opts.rx;
+ if (cinfo.saw_Adobe_marker)
+ {
+ for (x = 0; x < ilp->opts.rw; x++)
+ {
+ /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */
+ /* that is C is replaces by 255 - C, etc...*/
+ /* See the comment below for the computation of RGB values from CMYK ones. */
+ *ptr2 =
+ (0xff000000) |
+ ((ptr[0] * ptr[3] / 255) << 16) |
+ ((ptr[1] * ptr[3] / 255) << 8) |
+ ((ptr[2] * ptr[3] / 255));
+ ptr += 4;
+ ptr2++;
+ }
+ }
+ else
+ {
+ for (x = 0; x < ilp->opts.rw; x++)
+ {
+ /* Conversion from CMYK to RGB is done in 2 steps: */
+ /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */
+ /* after computation, if C, M, Y and K are between 0 and 1, we have: */
+ /* R = (1 - C) * (1 - K) * 255 */
+ /* G = (1 - M) * (1 - K) * 255 */
+ /* B = (1 - Y) * (1 - K) * 255 */
+ /* libjpeg stores CMYK values between 0 and 255, */
+ /* so we replace C by C * 255 / 255, etc... and we obtain: */
+ /* R = (255 - C) * (255 - K) / 255 */
+ /* G = (255 - M) * (255 - K) / 255 */
+ /* B = (255 - Y) * (255 - K) / 255 */
+ /* with C, M, Y and K between 0 and 255. */
+ *ptr2 =
+ (0xff000000) |
+ (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
+ (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
+ (((255 - ptr[2]) * (255 - ptr[3]) / 255));
+ ptr += 4;
+ ptr2++;
+ }
+ }
+ ptr += (4 * (w - (ilp->opts.rx + ilp->opts.rw)));
+ }
+ else
+ ptr += (4 * w);
+ }
+ }
+ }
+ }
+ }
+ /* We handle then RGB with 3 components */
+ else if (cinfo.output_components == 3)
+ {
+/*
+ double t;
+ if (region)
+ {
+ // debug for now
+ printf("R| %p %5ix%5i %s: %5i %5i %5ix%5i - ",
+ ie,
+ ie->w, ie->h,
+ ie->file,
+ ilp->opts.rx,
+ ilp->opts.ry,
+ ilp->opts.rw,
+ ilp->opts.rh);
+ }
+ t = get_time();
+ */
+ for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
+ line[i] = data + (i * w * 3);
+ for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+ {
+ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+ scans = cinfo.rec_outbuf_height;
+ if ((h - l) < scans) scans = h - l;
+ ptr = data;
+ if (!region)
+ {
+ for (y = 0; y < scans; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]);
+ ptr += 3;
+ ptr2++;
+ }
+ }
+ }
+ else
+ {
+ // if line # > region last line, break
+ // but not return immediately for rotation job
+ if (l >= (ilp->opts.ry + ilp->opts.rh))
+ {
+ line_done = EINA_TRUE;
+ /* if rotation flag is set , we have to rotate image */
+ goto done;
+ }
+ // else if scan block intersects region start or later
+ else if ((l + scans) >
+ (ilp->opts.ry))
+ {
+ for (y = 0; y < scans; y++)
+ {
+ if (((y + l) >= ilp->opts.ry) &&
+ ((y + l) < (ilp->opts.ry + ilp->opts.rh)))
+ {
+ ptr += (3 * ilp->opts.rx);
+ for (x = 0; x < ilp->opts.rw; x++)
+ {
+ *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]);
+ ptr += 3;
+ ptr2++;
+ }
+ ptr += (3 * (w - (ilp->opts.rx + ilp->opts.rw)));
+ }
+ else
+ ptr += (3 * w);
+ }
+ }
+ }
+ }
+/*
+ t = get_time() - t;
+ printf("%3.3f\n", t);
+ */
+ }
+ /* We finally handle RGB with 1 component */
+ else if (cinfo.output_components == 1)
+ {
+ for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
+ line[i] = data + (i * w);
+ for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+ {
+ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+ scans = cinfo.rec_outbuf_height;
+ if ((h - l) < scans) scans = h - l;
+ ptr = data;
+ if (!region)
+ {
+ for (y = 0; y < scans; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]);
+ ptr++;
+ ptr2++;
+ }
+ }
+ }
+ else
+ {
+ // if line # > region last line, break
+ if (l >= (ilp->opts.ry + ilp->opts.rh))
+ {
+ line_done = EINA_TRUE;
+ /* if rotation flag is set , we have to rotate image */
+ goto done;
+ /*jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = NONE;
+ return EINA_TRUE;*/
+ }
+ // els if scan block intersects region start or later
+ else if ((l + scans) >
+ (ilp->opts.ry))
+ {
+ for (y = 0; y < scans; y++)
+ {
+ if (((y + l) >= ilp->opts.ry) &&
+ ((y + l) < (ilp->opts.ry + ilp->opts.rh)))
+ {
+ ptr += ilp->opts.rx;
+ for (x = 0; x < ilp->opts.rw; x++)
+ {
+ *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]);
+ ptr++;
+ ptr2++;
+ }
+ ptr += w - (ilp->opts.rx + ilp->opts.rw);
+ }
+ else
+ ptr += w;
+ }
+ }
+ }
+ }
+ }
+ /* if rotation operation need, rotate it */
+done:
+
+ if (ilp->rotated)
+ {
+ DATA32 *data1, *data2, *to, *from;
+ int lx, ly, lw, lh, hw;
+
+ if (change_wh)
+ {
+ tmp = ilp->w;
+ ilp->w = ilp->h;
+ ilp->h = tmp;
+ }
+
+ lw = ilp->w;
+ lh = ilp->h;
+ hw = lw * lh;
+
+ data1 = ilp->buffer;
+
+ if (degree == 180)
+ {
+ DATA32 tmpd;
+
+ data2 = data1 + (lh * lw) -1;
+ for (lx = (lw * lh) / 2; --lx >= 0;)
+ {
+ tmpd = *data1;
+ *data1 = *data2;
+ *data2 = tmpd;
+ data1++;
+ data2--;
+ }
+ }
+ else
+ {
+ data2 = NULL;
+ to = NULL;
+ if (ptr_rotate) data2 = ptr_rotate;
+
+ if (degree == 90)
+ {
+ to = data1 + lw - 1;
+ hw = -hw - 1;
+ }
+ else if (degree == 270)
+ {
+ to = data1 + hw - lw;
+ lw = -lw;
+ hw = hw + 1;
+ }
+
+ if (to)
+ {
+ from = data2;
+ for (lx = ilp->w; --lx >= 0;)
+ {
+ for (ly = ilp->h; --ly >= 0;)
+ {
+ *to = *from;
+ from++;
+ to += lw;
+ }
+ to += hw;
+ }
+ }
+ if (ptr_rotate)
+ {
+ free(ptr_rotate);
+ ptr_rotate = NULL;
+ }
+ }
+ if (region)
+ {
+ ilp->opts.rx = load_region_x;
+ ilp->opts.ry = load_region_y;
+ ilp->opts.rw = load_region_w;
+ ilp->opts.rh = load_region_h;
+ }
+ }
+ if (line_done)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_NONE;
+ return EINA_FALSE;
+ }
+ /* end data decoding */
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = CSERVE2_NONE;
+ return EINA_TRUE;
+}
+
+Eina_Bool
+evas_image_load_file_head_jpeg(Evas_Img_Load_Params *ilp,
+ const char *file, const char *key __UNUSED__,
+ int *error)
+{
+ Eina_File *f;
+ void *map;
+ Eina_Bool val = EINA_FALSE;
+
+ f = eina_file_open(file, EINA_FALSE);
+ if (!f)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+ map = eina_file_map_all(f, EINA_FILE_WILLNEED);
+ if (!map)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ goto on_error;
+ }
+
+ val = evas_image_load_file_head_jpeg_internal(ilp,
+ map, eina_file_size_get(f),
+ error);
+
+ eina_file_map_free(f, map);
+
+ on_error:
+ eina_file_close(f);
+ return val;
+}
+
+static Eina_Bool
+evas_image_load_file_data_jpeg(Evas_Img_Load_Params *ilp,
+ const char *file, const char *key __UNUSED__,
+ int *error)
+{
+ Eina_File *f;
+ void *map;
+ Eina_Bool val = EINA_FALSE;
+
+ f = eina_file_open(file, EINA_FALSE);
+ if (!f)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+ map = eina_file_map_all(f, EINA_FILE_WILLNEED);
+ if (!map)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ goto on_error;
+ }
+
+ val = evas_image_load_file_data_jpeg_internal(ilp,
+ map, eina_file_size_get(f),
+ error);
+
+ eina_file_map_free(f, map);
+
+ on_error:
+ eina_file_close(f);
+ return val;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "jpeg",
+ evas_image_load_file_head_jpeg,
+ evas_image_load_file_data_jpeg
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@evas_image_loader_pmaps_cflags@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_PMAPS
+#if !EVAS_STATIC_BUILD_PMAPS
+
+pkgdir = $(libdir)/evas/cserve2/loaders/pmaps/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_pmaps.c
+
+module_la_LIBADD = @evas_image_loader_pmaps_libs@ @EINA_LIBS@ @EVIL_LIBS@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_pmaps.la
+#libevas_loader_pmaps_la_SOURCES = evas_image_load_pmaps.c
+#libevas_loader_pmaps_la_LIBADD = @evas_image_loader_pmaps_libs@
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include <ctype.h>
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+#define FILE_BUFFER_SIZE 1024 * 32
+#define FILE_BUFFER_UNREAD_SIZE 16
+
+/* The buffer to load pmaps images */
+typedef struct Pmaps_Buffer Pmaps_Buffer;
+
+struct Pmaps_Buffer
+{
+ Eina_File *file;
+ void *map;
+ size_t position;
+
+ /* the buffer */
+ DATA8 buffer[FILE_BUFFER_SIZE];
+ DATA8 unread[FILE_BUFFER_UNREAD_SIZE];
+ DATA8 *current;
+ DATA8 *end;
+ char type[3];
+ unsigned char unread_len:7;
+ unsigned char last_buffer:1;
+
+ /* image properties */
+ int w;
+ int h;
+ int max;
+
+ /* interface */
+ int (*int_get) (Pmaps_Buffer *b, int *val);
+ int (*color_get) (Pmaps_Buffer *b, DATA32 *color);
+};
+
+/* internal used functions */
+static Eina_Bool pmaps_buffer_open(Pmaps_Buffer *b, const char *filename, int *error);
+static void pmaps_buffer_close(Pmaps_Buffer *b);
+static Eina_Bool pmaps_buffer_header_parse(Pmaps_Buffer *b, int *error);
+static int pmaps_buffer_plain_int_get(Pmaps_Buffer *b, int *val);
+static int pmaps_buffer_1byte_int_get(Pmaps_Buffer *b, int *val);
+static int pmaps_buffer_2byte_int_get(Pmaps_Buffer *b, int *val);
+static int pmaps_buffer_gray_get(Pmaps_Buffer *b, DATA32 *color);
+static int pmaps_buffer_rgb_get(Pmaps_Buffer *b, DATA32 *color);
+static int pmaps_buffer_plain_bw_get(Pmaps_Buffer *b, DATA32 *color);
+
+static size_t pmaps_buffer_plain_update(Pmaps_Buffer *b);
+static size_t pmaps_buffer_raw_update(Pmaps_Buffer *b);
+static int pmaps_buffer_comment_skip(Pmaps_Buffer *b);
+
+static Eina_Bool
+evas_image_load_file_head_pmaps(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ Pmaps_Buffer b;
+
+ if (!pmaps_buffer_open(&b, file, error))
+ {
+ pmaps_buffer_close(&b);
+ return EINA_FALSE;
+ }
+
+ if (!pmaps_buffer_header_parse(&b, error))
+ {
+ pmaps_buffer_close(&b);
+ return EINA_FALSE;
+ }
+
+ ilp->w = b.w;
+ ilp->h = b.h;
+
+ pmaps_buffer_close(&b);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_pmaps(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ Pmaps_Buffer b;
+ int pixels;
+ DATA32 *ptr;
+
+ if (!pmaps_buffer_open(&b, file, error))
+ {
+ pmaps_buffer_close(&b);
+ return EINA_FALSE;
+ }
+
+ if (!pmaps_buffer_header_parse(&b, error))
+ {
+ pmaps_buffer_close(&b);
+ return EINA_FALSE;
+ }
+
+ pixels = b.w * b.h;
+
+ ptr = ilp->buffer;
+ if (!ptr)
+ {
+ pmaps_buffer_close(&b);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ if (b.type[1] != '4')
+ {
+ while (pixels > 0 && b.color_get(&b, ptr))
+ {
+ pixels--;
+ ptr++;
+ }
+ }
+ else
+ {
+ while (pixels > 0
+ && (b.current != b.end || pmaps_buffer_raw_update(&b)))
+ {
+ int i;
+
+ for (i = 7; i >= 0 && pixels > 0; i--)
+ {
+ if (*b.current & (1 << i))
+ *ptr = 0xff000000;
+ else
+ *ptr = 0xffffffff;
+ ptr++;
+ pixels--;
+ }
+ b.current++;
+ }
+ }
+
+ /* if there are some pix missing, give them a proper default */
+ memset(ptr, 0xff, 4 * pixels);
+ pmaps_buffer_close(&b);
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+/* internal used functions */
+static Eina_Bool
+pmaps_buffer_open(Pmaps_Buffer *b, const char *filename, int *error)
+{
+ size_t len;
+
+ b->file = eina_file_open(filename, EINA_FALSE);
+ if (!b->file)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ b->map = eina_file_map_all(b->file, EINA_FILE_SEQUENTIAL);
+ if (!b->map)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ eina_file_close(b->file);
+ b->file = NULL;
+ return EINA_FALSE;
+ }
+
+ b->position = 0;
+ *b->buffer = 0;
+ *b->unread = 0;
+ b->last_buffer = 0;
+ b->unread_len = 0;
+
+ len = pmaps_buffer_plain_update(b);
+
+ if (len < 3)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ eina_file_map_free(b->file, b->map);
+ eina_file_close(b->file);
+ b->map = NULL;
+ b->file = NULL;
+ return EINA_FALSE;
+ }
+
+ /* copy the type */
+ b->type[0] = b->buffer[0];
+ b->type[1] = b->buffer[1];
+ b->type[2] = 0;
+ /* skip the PX */
+ b->current = b->buffer + 2;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+static void
+pmaps_buffer_close(Pmaps_Buffer *b)
+{
+ if (b->file)
+ {
+ if (b->map) eina_file_map_free(b->file, b->map);
+ b->map = NULL;
+ eina_file_close(b->file);
+ b->file = NULL;
+ }
+}
+
+static Eina_Bool
+pmaps_buffer_header_parse(Pmaps_Buffer *b, int *error)
+{
+ /* if there is no P at the beginning it is not a file we can parse */
+ if (b->type[0] != 'P')
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ /* get the width */
+ if (!pmaps_buffer_plain_int_get(b, &(b->w)) || b->w < 1)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ /* get the height */
+ if (!pmaps_buffer_plain_int_get(b, &(b->h)) || b->h < 1)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ /* get the maximum value. P1 and P4 don't have a maximum value. */
+ if (!(b->type[1] == '1' || b->type[1] == '4')
+ && (!pmaps_buffer_plain_int_get(b, &(b->max)) || b->max < 1))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ /* set up the color get callback */
+ switch (b->type[1])
+ {
+ /* Black and White */
+ case '1':
+ b->color_get = pmaps_buffer_plain_bw_get;
+ break;
+ case '4':
+ /* Binary black and white use another format */
+ b->color_get = NULL;
+ break;
+ case '2':
+ case '5':
+ b->color_get = pmaps_buffer_gray_get;
+ break;
+ case '3':
+ case '6':
+ b->color_get = pmaps_buffer_rgb_get;
+ break;
+ case '7':
+ /* XXX write me */
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ /* set up the int get callback */
+ switch (b->type[1])
+ {
+ /* RAW */
+ case '5':
+ case '6':
+ if (b->max < 256)
+ b->int_get = pmaps_buffer_1byte_int_get;
+ else
+ b->int_get = pmaps_buffer_2byte_int_get;
+
+ if (b->current == b->end && !pmaps_buffer_raw_update(b))
+ return 0;
+
+ b->current++;
+ break;
+ /* Plain */
+ case '2':
+ case '3':
+ b->int_get = pmaps_buffer_plain_int_get;
+ break;
+ /* Black and White Bitmaps don't use that callback */
+ case '1':
+ case '4':
+ b->int_get = NULL;
+ /* we need to skip the next character fpr P4 it
+ * doesn't hurt if we do it for the P1 as well */
+ b->current++;
+ break;
+ }
+ return 1;
+}
+
+static size_t
+pmaps_buffer_plain_update(Pmaps_Buffer *b)
+{
+ size_t r;
+ size_t max;
+
+ /* if we already are in the last buffer we can not update it */
+ if (b->last_buffer)
+ return 0;
+
+ /* if we have unread bytes we need to put them before the new read
+ * stuff */
+ if (b->unread_len)
+ memcpy(b->buffer, b->unread, b->unread_len);
+
+ max = FILE_BUFFER_SIZE - b->unread_len - 1;
+ if (b->position + max > eina_file_size_get(b->file))
+ max = eina_file_size_get(b->file) - b->position;
+
+ memcpy(&b->buffer[b->unread_len], b->map + b->position, max);
+ b->position += max;
+ r = max + b->unread_len;
+
+ /* we haven't read anything nor have we bytes in the unread buffer */
+ if (r == 0)
+ {
+ b->buffer[0] = '\0';
+ b->end = b->buffer;
+ b->last_buffer = 1;
+ return 0;
+ }
+
+ if (r < FILE_BUFFER_SIZE - 1)
+ {
+ /*we reached eof */ ;
+ b->last_buffer = 1;
+ }
+
+ b->buffer[r] = 0;
+
+ b->unread[0] = '\0';
+ b->unread_len = 0;
+
+ b->buffer[r] = '\0';
+ b->current = b->buffer;
+ b->end = b->buffer + r;
+
+ return r;
+}
+
+static size_t
+pmaps_buffer_raw_update(Pmaps_Buffer *b)
+{
+ size_t r;
+ size_t max;
+
+ if (b->last_buffer)
+ return 0;
+
+ if (b->unread_len)
+ memcpy(b->buffer, b->unread, b->unread_len);
+
+ max = FILE_BUFFER_SIZE - b->unread_len;
+ if (b->position + max > eina_file_size_get(b->file))
+ max = eina_file_size_get(b->file) - b->position;
+
+ memcpy(&b->buffer[b->unread_len], b->map + b->position, max);
+ b->position += max;
+ r = max + b->unread_len;
+
+ if (r < FILE_BUFFER_SIZE)
+ {
+ /*we reached eof */
+ b->last_buffer = 1;
+ }
+
+ b->end = b->buffer + r;
+ b->current = b->buffer;
+
+ if (b->unread_len)
+ {
+ /* the buffer is now read */
+ *b->unread = 0;
+ b->unread_len = 0;
+ }
+
+ return r;
+}
+
+static int
+pmaps_buffer_plain_int_get(Pmaps_Buffer *b, int *val)
+{
+ char *start;
+ DATA8 lastc;
+
+ /* first skip all white space
+ * Note: we are skipping here actually every character than is not
+ * a digit */
+ while (!isdigit(*b->current))
+ {
+ if (*b->current == '\0')
+ {
+ if (!pmaps_buffer_plain_update(b))
+ return 0;
+
+ continue;
+ }
+ if (*b->current == '#' && !pmaps_buffer_comment_skip(b))
+ return 0;
+ b->current++;
+ }
+
+ start = (char *)b->current;
+ /* now find the end of the number */
+ while (isdigit(*b->current))
+ b->current++;
+
+ lastc = *b->current;
+ *b->current = '\0';
+ *val = atoi(start);
+ *b->current = lastc;
+
+ return 1;
+}
+
+static int
+pmaps_buffer_1byte_int_get(Pmaps_Buffer *b, int *val)
+{
+ /* are we at the end of the buffer? */
+ if (b->current == b->end && !pmaps_buffer_raw_update(b))
+ return 0;
+
+ *val = *b->current;
+ b->current++;
+
+ return 1;
+}
+static int
+pmaps_buffer_2byte_int_get(Pmaps_Buffer *b, int *val)
+{
+ /* are we at the end of the buffer? */
+ if (b->current == b->end && !pmaps_buffer_raw_update(b))
+ return 0;
+
+ *val = (int)(*b->current << 8);
+ b->current++;
+
+ /* are we at the end of the buffer? */
+ if (b->current == b->end && !pmaps_buffer_raw_update(b))
+ return 0;
+
+ *val |= *b->current;
+ b->current++;
+
+ return 1;
+}
+
+static int
+pmaps_buffer_comment_skip(Pmaps_Buffer *b)
+{
+ while (*b->current != '\n')
+ {
+ if (*b->current == '\0')
+ {
+ if (!pmaps_buffer_plain_update(b))
+ return 0;
+
+ continue;
+ }
+ b->current++;
+ }
+ return 1;
+}
+
+static int
+pmaps_buffer_rgb_get(Pmaps_Buffer *b, DATA32 *color)
+{
+ int vr, vg, vb;
+
+ if (!b->int_get(b, &vr) || !b->int_get(b, &vg) || !b->int_get(b, &vb))
+ return 0;
+
+ if (b->max != 255)
+ {
+ vr = (vr * 255) / b->max;
+ vg = (vg * 255) / b->max;
+ vb = (vb * 255) / b->max;
+ }
+ if (vr > 255)
+ vr = 255;
+ if (vg > 255)
+ vg = 255;
+ if (vb > 255)
+ vb = 255;
+
+ *color = ARGB_JOIN(0xff, vr, vg, vb);
+
+ return 1;
+}
+
+static int
+pmaps_buffer_gray_get(Pmaps_Buffer *b, DATA32 *color)
+{
+ int val;
+
+ if (!b->int_get(b, &val))
+ return 0;
+
+ if (b->max != 255)
+ val = (val * 255) / b->max;
+ if (val > 255)
+ val = 255;
+ *color = ARGB_JOIN(0xff, val, val, val);
+
+ return 1;
+}
+
+static int
+pmaps_buffer_plain_bw_get(Pmaps_Buffer *b, DATA32 *val)
+{
+ /* first skip all white space
+ * Note: we are skipping here actually every character than is not
+ * a digit */
+ while (!isdigit(*b->current))
+ {
+ if (*b->current == '\0')
+ {
+ if (!pmaps_buffer_raw_update(b))
+ return 0;
+
+ continue;
+ }
+ if (*b->current == '#' && !pmaps_buffer_comment_skip(b))
+ return 0;
+ b->current++;
+ }
+
+ if (*b->current == '0')
+ *val = 0xffffffff;
+ else
+ *val = 0xff000000;
+
+ b->current++;
+
+ return 1;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "pmaps",
+ evas_image_load_file_head_pmaps,
+ evas_image_load_file_data_pmaps
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@evas_image_loader_png_cflags@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_PNG
+#if !EVAS_STATIC_BUILD_PNG
+
+pkgdir = $(libdir)/evas/cserve2/loaders/png/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_png.c
+
+module_la_LIBADD = @EINA_LIBS@ @evas_image_loader_png_libs@ @EVIL_LIBS@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_png.la
+#libevas_loader_png_la_SOURCES = evas_image_load_png.c
+#libevas_loader_png_la_LIBADD = @evas_image_loader_png_libs@
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <png.h>
+#include <setjmp.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#ifdef _WIN32_WCE
+# define E_FOPEN(file, mode) evil_fopen_native((file), (mode))
+# define E_FREAD(buffer, size, count, stream) evil_fread_native(buffer, size, count, stream)
+# define E_FCLOSE(stream) evil_fclose_native(stream)
+#else
+# define E_FOPEN(file, mode) fopen((file), (mode))
+# define E_FREAD(buffer, size, count, stream) fread(buffer, size, count, stream)
+# define E_FCLOSE(stream) fclose(stream)
+#endif
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+#define PNG_BYTES_TO_CHECK 4
+
+
+static Eina_Bool
+evas_image_load_file_head_png(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ png_uint_32 w32, h32;
+ FILE *f;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ int bit_depth, color_type, interlace_type;
+ unsigned char buf[PNG_BYTES_TO_CHECK];
+ char hasa;
+
+ hasa = 0;
+ f = E_FOPEN(file, "rb");
+ if (!f)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ /* if we havent read the header before, set the header data */
+ if (E_FREAD(buf, PNG_BYTES_TO_CHECK, 1, f) != 1)
+ {
+ *error = CSERVE2_UNKNOWN_FORMAT;
+ goto close_file;
+ }
+
+ if (png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK))
+ {
+ *error = CSERVE2_UNKNOWN_FORMAT;
+ goto close_file;
+ }
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ *error = CSERVE2_CORRUPT_FILE;
+ goto close_file;
+ }
+ png_init_io(png_ptr, f);
+ png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
+ (png_uint_32 *) (&h32), &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+ if ((w32 < 1) || (h32 < 1) || (w32 > IMG_MAX_SIZE) || (h32 > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w32, h32))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ if (IMG_TOO_BIG(w32, h32))
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = CSERVE2_GENERIC;
+ goto close_file;
+ }
+ if (ilp->opts.scale_down_by > 1)
+ {
+ ilp->w = (int) w32 / ilp->opts.scale_down_by;
+ ilp->h = (int) h32 / ilp->opts.scale_down_by;
+ if ((ilp->w < 1) || (ilp->h < 1))
+ {
+ *error = CSERVE2_GENERIC;
+ goto close_file;
+ }
+ }
+ else
+ {
+ ilp->w = (int) w32;
+ ilp->h = (int) h32;
+ }
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1;
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
+ if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
+ if (hasa) ilp->alpha = 1;
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ E_FCLOSE(f);
+
+ *error = CSERVE2_NONE;
+ return EINA_TRUE;
+
+ close_file:
+ E_FCLOSE(f);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_png(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ unsigned char *surface;
+ png_uint_32 w32, h32;
+ int w, h;
+ FILE *f;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ int bit_depth, color_type, interlace_type;
+ unsigned char buf[PNG_BYTES_TO_CHECK];
+ unsigned char **lines;
+ char hasa;
+ int i, j;
+ int scale_ratio = 1, image_w = 0;
+ unsigned char *tmp_line;
+ DATA32 *src_ptr, *dst_ptr;
+
+ hasa = 0;
+ f = E_FOPEN(file, "rb");
+ if (!f)
+ {
+ *error = CSERVE2_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ /* if we havent read the header before, set the header data */
+ if (E_FREAD(buf, PNG_BYTES_TO_CHECK, 1, f) != 1)
+ {
+ *error = CSERVE2_CORRUPT_FILE;
+ goto close_file;
+ }
+ if (png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK))
+ {
+ *error = CSERVE2_CORRUPT_FILE;
+ goto close_file;
+ }
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ *error = CSERVE2_CORRUPT_FILE;
+ goto close_file;
+ }
+ png_init_io(png_ptr, f);
+ png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
+ (png_uint_32 *) (&h32), &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+ image_w = w32;
+ if (ilp->opts.scale_down_by > 1)
+ {
+ scale_ratio = ilp->opts.scale_down_by;
+ w32 /= scale_ratio;
+ h32 /= scale_ratio;
+ }
+ surface = (unsigned char *) ilp->buffer;
+ if (!surface)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ *error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ if ((w32 != ilp->w) || (h32 != ilp->h))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ *error = CSERVE2_GENERIC;
+ goto close_file;
+ }
+
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1;
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
+ if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
+ if (hasa) ilp->alpha = 1;
+
+ /* Prep for transformations... ultimately we want ARGB */
+ /* expand palette -> RGB if necessary */
+ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
+ /* expand gray (w/reduced bits) -> 8-bit RGB if necessary */
+ if ((color_type == PNG_COLOR_TYPE_GRAY) ||
+ (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
+ {
+ png_set_gray_to_rgb(png_ptr);
+ if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
+ }
+ /* expand transparency entry -> alpha channel if present */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(png_ptr);
+ /* reduce 16bit color -> 8bit color if necessary */
+ if (bit_depth > 8) png_set_strip_16(png_ptr);
+ /* pack all pixels to byte boundaries */
+ png_set_packing(png_ptr);
+
+ w = ilp->w;
+ h = ilp->h;
+ /* we want ARGB */
+#ifdef WORDS_BIGENDIAN
+ png_set_swap_alpha(png_ptr);
+ if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
+#else
+ png_set_bgr(png_ptr);
+ if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+#endif
+
+ /* we read image line by line if scale down was set */
+ if (scale_ratio == 1)
+ {
+ lines = (unsigned char **) alloca(h * sizeof(unsigned char *));
+ for (i = 0; i < h; i++)
+ lines[i] = surface + (i * w * sizeof(DATA32));
+ png_read_image(png_ptr, lines);
+ png_read_end(png_ptr, info_ptr);
+ }
+ else
+ {
+ tmp_line = (unsigned char *) alloca(image_w * sizeof(DATA32));
+ dst_ptr = (DATA32 *)surface;
+ for (i = 0; i < h; i++)
+ {
+ png_read_row(png_ptr, tmp_line, NULL);
+ src_ptr = (DATA32 *)tmp_line;
+ for (j = 0; j < w; j++)
+ {
+ *dst_ptr = *src_ptr;
+ dst_ptr++;
+ src_ptr += scale_ratio;
+ }
+ for (j = 0; j < (scale_ratio - 1); j++)
+ {
+ png_read_row(png_ptr, tmp_line, NULL);
+ }
+ }
+ }
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ E_FCLOSE(f);
+ evas_cserve2_image_premul(ilp);
+
+ *error = CSERVE2_NONE;
+ return EINA_TRUE;
+
+ close_file:
+ E_FCLOSE(f);
+ return EINA_FALSE;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "png",
+ evas_image_load_file_head_png,
+ evas_image_load_file_data_png
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_PSD
+#if !EVAS_STATIC_BUILD_PSD
+
+pkgdir = $(libdir)/evas/cserve2/loaders/psd/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_psd.c
+
+module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_psd.la
+#libevas_loader_psd_la_SOURCES = evas_image_load_psd.c
+#libevas_loader_psd_la_LIBADD =
+
+#endif
+endif
--- /dev/null
+#define _XOPEN_SOURCE
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+typedef struct _PSD_Header PSD_Header;
+
+typedef enum _PSD_Mode
+ {
+ PSD_GREYSCALE = 1,
+ PSD_INDEXED = 2,
+ PSD_RGB = 3,
+ PSD_CMYK = 4
+ } PSD_Mode;
+
+struct _PSD_Header
+{
+ unsigned char signature[4];
+ unsigned short version;
+ unsigned char reserved[9];
+ unsigned short channels;
+ unsigned int height;
+ unsigned int width;
+ unsigned short depth;
+
+ unsigned short channel_num;
+
+ PSD_Mode mode;
+};
+
+enum {
+ READ_COMPRESSED_SUCCESS,
+ READ_COMPRESSED_ERROR_FILE_CORRUPT,
+ READ_COMPRESSED_ERROR_FILE_READ_ERROR
+};
+
+static Eina_Bool get_compressed_channels_length(PSD_Header *Head,
+ const unsigned char *map, size_t length, size_t *position,
+ unsigned short *rle_table,
+ unsigned int *chanlen);
+
+static int
+read_ushort(const unsigned char *map, size_t length, size_t *position, unsigned short *ret)
+{
+ if (*position + 2 > length) return 0;
+ // FIXME: need to check order
+ *ret = (map[(*position) + 0] << 8) | map[(*position) + 1];
+ *position += 2;
+ return 1;
+}
+
+static int
+read_uint(const unsigned char *map, size_t length, size_t *position, unsigned int *ret)
+{
+ if (*position + 4 > length) return 0;
+ // FIXME: need to check order
+ *ret = ARGB_JOIN(map[(*position) + 0], map[(*position) + 1], map[(*position) + 2], map[(*position) + 3]);
+ *position += 4;
+ return 1;
+}
+
+static int
+read_block(const unsigned char *map, size_t length, size_t *position, void *target, size_t size)
+{
+ if (*position + size > length) return 0;
+ memcpy(target, map + *position, size);
+ *position += size;
+ return 1;
+}
+
+// Internal function used to get the Psd header from the current file.
+Eina_Bool
+psd_get_header(PSD_Header *header, const unsigned char *map, size_t length, size_t *position)
+{
+ unsigned short tmp;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ CHECK_RET(read_block(map, length, position, header->signature, 4));
+ CHECK_RET(read_ushort(map, length, position, &header->version));
+ CHECK_RET(read_block(map, length, position, header->reserved, 6));
+ CHECK_RET(read_ushort(map, length, position, &header->channels));
+ CHECK_RET(read_uint(map, length, position, &header->height));
+ CHECK_RET(read_uint(map, length, position, &header->width));
+ CHECK_RET(read_ushort(map, length, position, &header->depth));
+
+ CHECK_RET(read_ushort(map, length, position, &tmp));
+ header->mode = tmp;
+
+#undef CHECK_RET
+
+ /* fprintf(stderr, "<<<<<<<<<<<\nsignature : %c%c%c%c\n", */
+ /* header->signature[0], */
+ /* header->signature[1], */
+ /* header->signature[2], */
+ /* header->signature[3]); */
+ /* fprintf(stderr, "version : %i\n", header->version); */
+ /* fprintf(stderr, "channels : %i\n", header->channels); */
+ /* fprintf(stderr, "width x height : %dx%d\n", header->width, header->height); */
+ /* fprintf(stderr, "depth : %i\n", header->depth); */
+ /* fprintf(stderr, "mode : %i\n>>>>>>>>>>>>\n", header->mode); */
+
+ return EINA_TRUE;
+}
+
+
+// Internal function used to check if the HEADER is a valid Psd header.
+Eina_Bool
+is_psd(PSD_Header *header)
+{
+ if (strncmp((char*)header->signature, "8BPS", 4))
+ return EINA_FALSE;
+ if (header->version != 1)
+ return EINA_FALSE;
+ if (header->channels < 1 || header->channels > 24)
+ return EINA_FALSE;
+ if (header->height < 1 || header->width < 1)
+ return EINA_FALSE;
+ if (header->depth != 1 && header->depth != 8 && header->depth != 16)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+evas_image_load_file_head_psd(Evas_Img_Load_Params *ilp, const char *FileName,
+ const char *key __UNUSED__, int *error)
+{
+ Eina_File *f;
+ void *map;
+ size_t length;
+ size_t position;
+ PSD_Header header;
+ Eina_Bool correct;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ f = eina_file_open(FileName, 0);
+ if (f == NULL)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ length = eina_file_size_get(f);
+ position = 0;
+ if (!map || length < 1)
+ {
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ correct = psd_get_header(&header, map, length, &position);
+
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+
+ if (!correct || !is_psd(&header))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ ilp->w = header.width;
+ ilp->h = header.height;
+ if (header.channels == 3) ilp->alpha = 0;
+ else ilp->alpha = 1;
+
+ return EINA_TRUE;
+}
+
+static unsigned int
+read_compressed_channel(const unsigned char *map, size_t length, size_t *position,
+ const unsigned int channel_length __UNUSED__,
+ unsigned int size,
+ unsigned char* channel)
+{
+ // FIXME: what does channel_length means, and why is it not used
+ unsigned int i;
+ char headbyte, c;
+
+#define CHECK_RET(Call) \
+ if (!Call) return READ_COMPRESSED_ERROR_FILE_READ_ERROR; \
+
+ for (i = 0; i < size; )
+ {
+ CHECK_RET(read_block(map, length, position, &headbyte, 1));
+
+ if (headbyte >= 0)
+ {
+ if (i + headbyte > size)
+ return READ_COMPRESSED_ERROR_FILE_CORRUPT;
+ CHECK_RET(read_block(map, length, position, channel + i, headbyte + 1));
+
+ i += headbyte + 1;
+ }
+ else if (headbyte >= -127 && headbyte <= -1)
+ {
+ int run;
+
+ CHECK_RET(read_block(map, length, position, &c, 1));
+
+ run = c;
+ /* if (run == -1) */
+ /* return READ_COMPRESSED_ERROR_FILE_READ_ERROR; */
+
+ if (i + (-headbyte + 1) > size)
+ return READ_COMPRESSED_ERROR_FILE_CORRUPT;
+
+ memset(channel + i, run, -headbyte + 1);
+ i += -headbyte + 1;
+ }
+ }
+
+#undef CHECK_RET
+
+ return READ_COMPRESSED_SUCCESS;
+}
+
+
+static Eina_Bool
+psd_get_data(PSD_Header *head,
+ const unsigned char *map, size_t length, size_t *position,
+ unsigned char *buffer, Eina_Bool compressed,
+ int *error)
+{
+ unsigned int c, x, y, numchan, bps, bpc, bpp;
+ unsigned int pixels_count;
+ unsigned char *channel = NULL;
+ unsigned char *data = NULL;
+
+ // Added 01-07-2009: This is needed to correctly load greyscale and
+ // paletted images.
+ switch (head->mode)
+ {
+ case PSD_GREYSCALE:
+ case PSD_INDEXED:
+ numchan = 1;
+ break;
+ default:
+ numchan = 3;
+ }
+
+ bpp = head->channels;
+ bpc = head->depth / 8;
+ pixels_count = head->width * head->height;
+
+ data = malloc(sizeof (unsigned char) * pixels_count * bpp);
+ if (!data) return EINA_FALSE;
+
+ channel = malloc(sizeof (unsigned char) * pixels_count * bpc);
+ if (!channel)
+ {
+ free(data);
+ return EINA_FALSE;
+ }
+
+ bps = head->width * head->channels * bpc;
+ // @TODO: Add support for this in, though I have yet to run across a .psd
+ // file that uses this.
+ if (compressed && bpc == 2)
+ {
+ free(data);
+ free(channel);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+#define CHECK_RET(Call) \
+ if (!Call) \
+ { \
+ free(data); \
+ free(channel); \
+ return EINA_FALSE; \
+ }
+
+ if (!compressed)
+ {
+ if (bpc == 1)
+ {
+ for (c = 0; c < numchan; c++)
+ {
+ unsigned char *tmp = channel;
+
+ CHECK_RET(read_block(map, length, position, tmp, pixels_count));
+
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp, tmp++)
+ {
+ data[y + x + c] = *tmp;
+ }
+ }
+ }
+
+ // Accumulate any remaining channels into a single alpha channel
+ //@TODO: This needs to be changed for greyscale images.
+ for (; c < head->channels; c++)
+ {
+ unsigned char *tmp = channel;
+
+ CHECK_RET(read_block(map, length, position, channel, pixels_count));
+
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp, tmp++)
+ {
+ unsigned short newval;
+
+ // previous formula was : (old / 255 * new / 255) * 255
+ newval = (*tmp) * data[y + x + 3];
+
+ data[y + x + 3] = newval >> 8;
+ }
+ }
+ }
+ }
+ else
+ {
+ int bps2;
+
+ bps2 = bps / 2;
+
+ // iCurImage->Bpc == 2
+ for (c = 0; c < numchan; c++)
+ {
+ unsigned short *shortptr = (unsigned short*) channel;
+
+ CHECK_RET(read_block(map, length, position, channel, pixels_count * 2));
+
+ for (y = 0; y < head->height * bps2; y += bps2)
+ {
+ for (x = 0; x < (unsigned int)bps2; x += bpp, shortptr++)
+ {
+ ((unsigned short*)data)[y + x + c] = *shortptr;
+ }
+ }
+ }
+
+ // Accumulate any remaining channels into a single alpha channel
+ //@TODO: This needs to be changed for greyscale images.
+ for (; c < head->channels; c++)
+ {
+ unsigned short *shortptr = (unsigned short*) channel;
+
+ CHECK_RET(read_block(map, length, position, channel, pixels_count * 2));
+
+ for (y = 0; y < head->height * bps2; y += bps2)
+ {
+ for (x = 0; x < (unsigned int)bps2; x += bpp, shortptr)
+ {
+ unsigned int newval;
+
+ newval = *shortptr * ((unsigned short*)data)[y + x + 3];
+
+ ((unsigned short*)data)[y + x + 3] = newval >> 16;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ unsigned short *rle_table;
+ unsigned int *chanlen;
+
+ rle_table = alloca(head->height * head->channel_num * sizeof (unsigned short));
+ chanlen = alloca(head->channel_num * sizeof (unsigned int));
+ if (!get_compressed_channels_length(head, map, length, position, rle_table, chanlen))
+ goto file_read_error;
+
+ for (c = 0; c < numchan; c++)
+ {
+ unsigned char *tmp = channel;
+ int err;
+
+ err = read_compressed_channel(map, length, position,
+ chanlen[c],
+ pixels_count,
+ channel);
+ if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
+ goto file_corrupt;
+ else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
+ goto file_read_error;
+
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp, tmp++)
+ {
+ data[y + x + c] = *tmp;
+ }
+ }
+ }
+
+ // Initialize the alpha channel to solid
+ //@TODO: This needs to be changed for greyscale images.
+ if (head->channels >= 4)
+ {
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp)
+ {
+ data[y + x + 3] = 255;
+ }
+ }
+
+ for (; c < head->channels; c++)
+ {
+ unsigned char *tmp = channel;
+ int err;
+
+ err = read_compressed_channel(map, length, position,
+ chanlen[c],
+ pixels_count,
+ channel);
+ if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
+ goto file_corrupt;
+ else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
+ goto file_read_error;
+
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp, tmp++)
+ {
+ unsigned short newval;
+
+ newval = *tmp * data[y + x + 3];
+
+ data[y + x + 3] = newval >> 8;
+ }
+ }
+ }
+ }
+ }
+
+ if (bpp == 3)
+ {
+ for (x = 0; x < pixels_count; x++)
+ {
+ buffer[x * 4 + 0] = data[x * 3 + 2];
+ buffer[x * 4 + 1] = data[x * 3 + 1];
+ buffer[x * 4 + 2] = data[x * 3 + 0];
+ buffer[x * 4 + 3] = 255;
+ }
+ }
+ else
+ {
+ // BRGA to RGBA
+ for (x= 0; x < pixels_count; x++)
+ {
+ buffer[x * 4 + 0] = data[x * 4 + 2];
+ buffer[x * 4 + 1] = data[x * 4 + 1];
+ buffer[x * 4 + 2] = data[x * 4 + 0];
+ buffer[x * 4 + 3] = data[x * 4 + 3];
+ }
+ }
+
+ free(channel);
+ free(data);
+ return EINA_TRUE;
+
+#undef CHECK_RET
+
+ file_corrupt:
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+ file_read_error:
+ free(channel);
+ free(data);
+
+ return EINA_FALSE;
+}
+
+
+static Eina_Bool
+get_single_channel(PSD_Header *head,
+ const unsigned char *map, size_t length, size_t *position,
+ unsigned char *buffer,
+ Eina_Bool compressed)
+{
+ unsigned int i, bpc;
+ char headbyte;
+ int c;
+ int pixels_count;
+
+ bpc = (head->depth / 8);
+ pixels_count = head->width * head->height;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ if (!compressed)
+ {
+ if (bpc == 1)
+ {
+ CHECK_RET(read_block(map, length, position, buffer, pixels_count));
+ }
+ else
+ { // Bpc == 2
+ CHECK_RET(read_block(map, length, position, buffer, pixels_count * 2));
+ }
+ }
+ else
+ {
+ for (i = 0; i < (unsigned int)pixels_count; )
+ {
+ CHECK_RET(read_block(map, length, position, &headbyte, 1));
+
+ if (headbyte >= 0)
+ { // && HeadByte <= 127
+ CHECK_RET(read_block(map, length, position, buffer + i, headbyte + 1));
+
+ i += headbyte + 1;
+ }
+ if (headbyte >= -127 && headbyte <= -1)
+ {
+ int run;
+
+ CHECK_RET(read_block(map, length, position, &c, 1));
+
+ run = c;
+ if (run == -1) return EINA_FALSE;
+
+ memset(buffer + i, run, -headbyte + 1);
+ i += -headbyte + 1;
+ }
+ }
+ }
+
+#undef CHECK_RET
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_psd_grey(Evas_Img_Load_Params *ilp, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
+{
+ unsigned int color_mode, resource_size, misc_info;
+ unsigned short compressed;
+ void *surface = NULL;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ CHECK_RET(read_uint(map, length, position, &color_mode));
+ // Skip over the 'color mode data section'
+ *position += color_mode;
+
+ CHECK_RET(read_uint(map, length, position, &resource_size));
+ // Read the 'image resources section'
+ *position += resource_size;
+
+ CHECK_RET(read_uint(map, length, position, &misc_info));
+ *position += misc_info;
+
+ CHECK_RET(read_ushort(map, length, position, &compressed));
+
+ ilp->w = head->width;
+ ilp->h = head->height;
+ if (head->channels == 3) ilp->alpha = 0;
+ else ilp->alpha = 1;
+
+ head->channel_num = head->channels;
+ // Temporary to read only one channel...some greyscale .psd files have 2.
+ head->channels = 1;
+
+ switch (head->depth)
+ {
+ case 8:
+ case 16:
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ surface = ilp->buffer;
+ if (!surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto cleanup_error;
+ }
+
+ if (!psd_get_data(head, map, length, position, surface, compressed, error))
+ goto cleanup_error;
+
+ return EINA_TRUE;
+
+#undef CHECK_RET
+
+ cleanup_error:
+ return EINA_FALSE;
+}
+
+
+Eina_Bool
+read_psd_indexed(Evas_Img_Load_Params *ilp, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
+{
+ unsigned int color_mode, resource_size, misc_info;
+ unsigned short compressed;
+ void *surface;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+#define CHECK_RET(Call) \
+ if (!(Call)) return EINA_FALSE;
+
+ CHECK_RET(read_uint(map, length, position, &color_mode));
+ CHECK_RET(!(color_mode % 3));
+ /*
+ Palette = (unsigned char*)malloc(Colormode);
+ if (Palette == NULL)
+ return EINA_FALSE;
+ if (fread(&Palette, 1, Colormode, file) != Colormode)
+ goto cleanup_error;
+ */
+ // Skip over the 'color mode data section'
+ *position += color_mode;
+
+ // Read the 'image resources section'
+ CHECK_RET(read_uint(map, length, position, &resource_size));
+ *position += resource_size;
+
+ CHECK_RET(read_uint(map, length, position, &misc_info));
+ *position += misc_info;
+
+ CHECK_RET(read_ushort(map, length, position, &compressed));
+
+ if (head->channels != 1 || head->depth != 8)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+ head->channel_num = head->channels;
+
+ ilp->w = head->width;
+ ilp->h = head->height;
+ if (head->channels == 3) ilp->alpha = 0;
+ else ilp->alpha = 1;
+
+ surface = ilp->buffer;
+ if (!surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ if (!psd_get_data(head, map, length, position, surface, compressed, error))
+ return EINA_FALSE;
+ return EINA_TRUE;
+
+#undef CHECK_RET
+}
+
+Eina_Bool
+read_psd_rgb(Evas_Img_Load_Params *ilp, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
+{
+ unsigned int color_mode, resource_size, misc_info;
+ unsigned short compressed;
+ void *surface;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ CHECK_RET(read_uint(map, length, position, &color_mode));
+ // Skip over the 'color mode data section'
+ *position += color_mode;
+
+ // Read the 'image resources section'
+ CHECK_RET(read_uint(map, length, position, &resource_size));
+ *position += resource_size;
+
+ CHECK_RET(read_uint(map, length, position, &misc_info));
+ *position += misc_info;
+
+ CHECK_RET(read_ushort(map, length, position, &compressed));
+
+ head->channel_num = head->channels;
+
+ switch (head->depth)
+ {
+ case 8:
+ case 16:
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+ ilp->w = head->width;
+ ilp->h = head->height;
+ if (head->channels == 3) ilp->alpha = 0;
+ else ilp->alpha = 1;
+
+ surface = ilp->buffer;
+ if (!surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto cleanup_error;
+ }
+
+ if (!psd_get_data(head, map, length, position, surface, compressed, error))
+ goto cleanup_error;
+
+ evas_cserve2_image_premul(ilp);
+ return EINA_TRUE;
+
+#undef CHECK_RET
+
+ cleanup_error:
+ return EINA_FALSE;
+}
+
+Eina_Bool
+read_psd_cmyk(Evas_Img_Load_Params *ilp, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
+{
+ unsigned int color_mode, resource_size, misc_info, size, j, data_size;
+ unsigned short compressed;
+ unsigned int format, type;
+ unsigned char *kchannel = NULL;
+ void *surface;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ CHECK_RET(read_uint(map, length, position, &color_mode));
+ // Skip over the 'color mode data section'
+ *position += color_mode;
+
+ CHECK_RET(read_uint(map, length, position, &resource_size));
+ // Read the 'image resources section'
+ *position += resource_size;
+
+ CHECK_RET(read_uint(map, length, position, &misc_info));
+ *position += misc_info;
+
+ CHECK_RET(read_ushort(map, length, position, &compressed));
+
+ switch (head->channels)
+ {
+ case 4:
+ format = 0x1907;
+ head->channel_num = 4;
+ head->channels = 3;
+ break;
+ case 5:
+ format = 0x1908;
+ head->channel_num = 5;
+ head->channels = 4;
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ switch (head->depth)
+ {
+ case 8:
+ type = 1;
+ break;
+ case 16:
+ type = 2;
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ ilp->w = head->width;
+ ilp->h = head->height;
+ if (head->channels == 3) ilp->alpha = 0;
+ else ilp->alpha = 1;
+
+ surface = ilp->buffer;
+ if (!surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto cleanup_error;
+ }
+
+ if (!psd_get_data(head, map, length, position, surface, compressed, error))
+ goto cleanup_error;
+
+ size = type * ilp->w * ilp->h;
+ kchannel = malloc(size);
+ if (kchannel == NULL)
+ goto cleanup_error;
+ if (!get_single_channel(head, map, length, position, kchannel, compressed))
+ goto cleanup_error;
+
+ data_size = head->channels * type * ilp->w * ilp->h;
+ if (format == 0x1907)
+ {
+ unsigned char *tmp = surface;
+ const unsigned char *limit = tmp + data_size;
+
+ for (j = 0; tmp < limit; tmp++, j++)
+ {
+ int k;
+
+ for (k = 0; k < 3; k++)
+ *tmp = (*tmp * kchannel[j]) >> 8;
+
+ // FIXME: tmp[i+3] = 255;
+ }
+ }
+ else
+ { // RGBA
+ unsigned char *tmp = surface;
+ const unsigned char *limit = tmp + data_size;
+
+ // The KChannel array really holds the alpha channel on this one.
+ for (j = 0; tmp < limit; tmp += 4, j++)
+ {
+ tmp[0] = (tmp[0] * tmp[3]) >> 8;
+ tmp[1] = (tmp[1] * tmp[3]) >> 8;
+ tmp[2] = (tmp[2] * tmp[3]) >> 8;
+ tmp[3] = kchannel[j]; // Swap 'K' with alpha channel.
+ }
+ }
+
+ free(kchannel);
+
+ evas_cserve2_image_premul(ilp);
+ return EINA_TRUE;
+
+ cleanup_error:
+ free(kchannel);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_psd(Evas_Img_Load_Params *ilp,
+ const char *file,
+ const char *key __UNUSED__,
+ int *error)
+{
+ Eina_File *f;
+ void *map;
+ size_t length;
+ size_t position;
+ PSD_Header header;
+ Eina_Bool bpsd = EINA_FALSE;
+
+ f = eina_file_open(file, 0);
+ if (f == NULL)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return bpsd;
+ }
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ length = eina_file_size_get(f);
+ position = 0;
+ if (!map || length < 1)
+ {
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ if (!psd_get_header(&header, map, length, &position) || !is_psd(&header))
+ {
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+
+ ilp->w = header.width;
+ ilp->h = header.height;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ switch (header.mode)
+ {
+ case PSD_GREYSCALE: // Greyscale
+ bpsd = read_psd_grey(ilp, &header, map, length, &position, error);
+ break;
+ case PSD_INDEXED: // Indexed
+ bpsd = read_psd_indexed(ilp, &header, map, length, &position, error);
+ break;
+ case PSD_RGB: // RGB
+ bpsd = read_psd_rgb(ilp, &header, map, length, &position, error);
+ break;
+ case PSD_CMYK: // CMYK
+ bpsd = read_psd_cmyk(ilp, &header, map, length, &position, error);
+ break;
+ default :
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ bpsd = EINA_FALSE;
+ }
+
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+
+ return bpsd;
+}
+
+static Eina_Bool
+get_compressed_channels_length(PSD_Header *head,
+ const unsigned char *map, size_t length, size_t *position,
+ unsigned short *rle_table,
+ unsigned int *chanlen)
+{
+ unsigned int j;
+ unsigned int c;
+
+ if (!read_block(map, length, position, rle_table,
+ sizeof (unsigned short) * head->height * head->channel_num))
+ return EINA_FALSE;
+
+ memset(chanlen, 0, head->channel_num * sizeof(unsigned int));
+ for (c = 0; c < head->channel_num; c++)
+ {
+ unsigned int i;
+
+ j = c * head->height;
+ for (i = 0; i < head->height; i++)
+ {
+ chanlen[c] += rle_table[i + j];
+ }
+ }
+
+ return EINA_TRUE;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "psd",
+ evas_image_load_file_head_psd,
+ evas_image_load_file_data_psd
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_TGA
+#if !EVAS_STATIC_BUILD_TGA
+
+pkgdir = $(libdir)/evas/cserve2/loaders/tga/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_tga.c
+
+module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_tga.la
+#libevas_loader_tga_la_SOURCES = evas_image_load_tga.c
+#libevas_loader_tga_la_LIBADD =
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+/* TGA pixel formats */
+#define TGA_TYPE_MAPPED 1 // handle
+#define TGA_TYPE_COLOR 2
+#define TGA_TYPE_GRAY 3
+#define TGA_TYPE_MAPPED_RLE 9 // handle
+#define TGA_TYPE_COLOR_RLE 10
+#define TGA_TYPE_GRAY_RLE 11
+
+/* TGA header flags */
+#define TGA_DESC_ABITS 0x0f
+#define TGA_DESC_HORIZONTAL 0x10
+#define TGA_DESC_VERTICAL 0x20
+
+#define TGA_SIGNATURE "TRUEVISION-XFILE"
+
+typedef struct _tga_header tga_header;
+typedef struct _tga_footer tga_footer;
+
+struct _tga_header
+{
+ unsigned char idLength;
+ unsigned char colorMapType;
+ unsigned char imageType;
+ unsigned char colorMapIndexLo, colorMapIndexHi;
+ unsigned char colorMapLengthLo, colorMapLengthHi;
+ unsigned char colorMapSize;
+ unsigned char xOriginLo, xOriginHi;
+ unsigned char yOriginLo, yOriginHi;
+ unsigned char widthLo, widthHi;
+ unsigned char heightLo, heightHi;
+ unsigned char bpp;
+ unsigned char descriptor;
+} __attribute__((packed));
+
+struct _tga_footer
+{
+ unsigned int extensionAreaOffset;
+ unsigned int developerDirectoryOffset;
+ char signature[16];
+ char dot;
+ char null;
+} __attribute__((packed));
+
+
+static Eina_Bool
+evas_image_load_file_head_tga(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ Eina_File *f;
+ unsigned char *seg = NULL, *filedata;
+ tga_header *header;
+ tga_footer *footer, tfooter;
+ char hasa = 0;
+ int w = 0, h = 0, bpp;
+ int x, y;
+
+ f = eina_file_open(file, EINA_FALSE);
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ if (f == NULL) return EINA_FALSE;
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ if (eina_file_size_get(f) < (off_t)(sizeof(tga_header) + sizeof(tga_footer)))
+ goto close_file;
+ seg = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (seg == NULL) goto close_file;
+ filedata = seg;
+
+ header = (tga_header *)filedata;
+ // no unaligned data accessed, so ok
+ footer = (tga_footer *)(filedata + (eina_file_size_get(f) - sizeof(tga_footer)));
+ memcpy((unsigned char *)(&tfooter),
+ (unsigned char *)footer,
+ sizeof(tga_footer));
+ //printf("0\n");
+ if (!memcmp(tfooter.signature, TGA_SIGNATURE, sizeof(tfooter.signature)))
+ {
+ if ((tfooter.dot == '.') && (tfooter.null == 0))
+ {
+ // footer is there and matches. this is a tga file - any problems now
+ // are a corrupt file
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ }
+ }
+// else goto close_file;
+ //printf("1\n");
+
+ filedata = (unsigned char *)filedata + sizeof(tga_header);
+ switch (header->imageType)
+ {
+ case TGA_TYPE_COLOR_RLE:
+ case TGA_TYPE_GRAY_RLE:
+// rle = 1;
+ break;
+ case TGA_TYPE_COLOR:
+ case TGA_TYPE_GRAY:
+// rle = 0;
+ break;
+ default:
+ goto close_file;
+ }
+ bpp = header->bpp;
+ if (!((bpp == 32) || (bpp == 24) || (bpp == 16) || (bpp == 8)))
+ goto close_file;
+ if ((bpp == 32) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
+ // don't handle colormapped images
+ if ((header->colorMapType) != 0)
+ goto close_file;
+ // if colormap size is anything other than legal sizes or 0 - not real tga
+ if (!((header->colorMapSize == 0) ||
+ (header->colorMapSize == 15) ||
+ (header->colorMapSize == 16) ||
+ (header->colorMapSize == 24) ||
+ (header->colorMapSize == 32)))
+ goto close_file;
+ x = (header->xOriginHi << 8) | (header->xOriginLo);
+ y = (header->yOriginHi << 8) | (header->yOriginLo);
+ w = (header->widthHi << 8) | header->widthLo;
+ h = (header->heightHi << 8) | header->heightLo;
+ // x origin gerater that width, y origin greater than height - wrong file
+ if ((x >= w) || (y >= h))
+ goto close_file;
+ // if descriptor has either of the top 2 bits set... not tga
+ if (header->descriptor & 0xc0)
+ goto close_file;
+
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ goto close_file;
+
+ ilp->w = w;
+ ilp->h = h;
+ if (hasa) ilp->alpha = 1;
+
+ eina_file_map_free(f, seg);
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+
+close_file:
+ if (seg != NULL) eina_file_map_free(f, seg);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_tga(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ Eina_File *f;
+ unsigned char *seg = NULL, *filedata;
+ tga_header *header;
+ tga_footer *footer, tfooter;
+ char hasa = 0, footer_present = 0, vinverted = 0, rle = 0;
+ int w = 0, h = 0, x, y, bpp;
+ off_t size;
+ unsigned int *surface, *dataptr;
+ unsigned int datasize;
+ unsigned char *bufptr, *bufend;
+ int abits;
+
+ f = eina_file_open(file, EINA_FALSE);
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ if (f == NULL) return EINA_FALSE;
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ if (eina_file_size_get(f) < (off_t)(sizeof(tga_header) + sizeof(tga_footer)))
+ goto close_file;
+ seg = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (seg == NULL) goto close_file;
+ filedata = seg;
+ size = eina_file_size_get(f);
+
+ header = (tga_header *)filedata;
+ // no unaligned data accessed, so ok
+ footer = (tga_footer *)(filedata + (size - sizeof(tga_footer)));
+ memcpy((unsigned char *)&tfooter,
+ (unsigned char *)footer,
+ sizeof(tga_footer));
+ if (!memcmp(tfooter.signature, TGA_SIGNATURE, sizeof(tfooter.signature)))
+ {
+ if ((tfooter.dot == '.') && (tfooter.null == 0))
+ {
+ // footer is there and matches. this is a tga file - any problems now
+ // are a corrupt file
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ footer_present = 1;
+ }
+ }
+
+ filedata = (unsigned char *)filedata + sizeof(tga_header);
+ vinverted = !(header->descriptor & TGA_DESC_VERTICAL);
+ switch (header->imageType)
+ {
+ case TGA_TYPE_COLOR_RLE:
+ case TGA_TYPE_GRAY_RLE:
+ rle = 1;
+ break;
+ case TGA_TYPE_COLOR:
+ case TGA_TYPE_GRAY:
+ rle = 0;
+ break;
+ default:
+ goto close_file;
+ }
+ bpp = header->bpp;
+ if (!((bpp == 32) || (bpp == 24) || (bpp == 16) || (bpp == 8)))
+ goto close_file;
+ if ((bpp == 32) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
+ abits = header->descriptor & TGA_DESC_ABITS;
+ // don't handle colormapped images
+ if ((header->colorMapType) != 0)
+ goto close_file;
+ // if colormap size is anything other than legal sizes or 0 - not real tga
+ if (!((header->colorMapSize == 0) ||
+ (header->colorMapSize == 15) ||
+ (header->colorMapSize == 16) ||
+ (header->colorMapSize == 24) ||
+ (header->colorMapSize == 32)))
+ goto close_file;
+ x = (header->xOriginHi << 8) | (header->xOriginLo);
+ y = (header->yOriginHi << 8) | (header->yOriginLo);
+ w = (header->widthHi << 8) | header->widthLo;
+ h = (header->heightHi << 8) | header->heightLo;
+ // x origin gerater that width, y origin greater than height - wrong file
+ if ((x >= w) || (y >= h))
+ goto close_file;
+ // if descriptor has either of the top 2 bits set... not tga
+ if (header->descriptor & 0xc0)
+ goto close_file;
+
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ goto close_file;
+
+ if ((w != (int)ilp->w) || (h != (int)ilp->h))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ surface = ilp->buffer;
+ if (!surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ datasize = size - sizeof(tga_header) - header->idLength;
+ if (footer_present)
+ datasize = size - sizeof(tga_header) - header->idLength -
+ sizeof(tga_footer);
+
+ bufptr = filedata + header->idLength;
+ bufend = filedata + datasize;
+
+ if (!rle)
+ {
+ for (y = 0; y < h; y++)
+ {
+ if (vinverted)
+ /* some TGA's are stored upside-down! */
+ dataptr = surface + ((h - y - 1) * w);
+ else
+ dataptr = surface + (y * w);
+ switch (bpp)
+ {
+ case 32:
+ for (x = 0; (x < w) && ((bufptr + 4) <= bufend); x++)
+ {
+ if (hasa)
+ {
+ int a = bufptr[3];
+
+ switch (abits)
+ {
+ case 1:
+ a = (a << 7) | (a << 6) | (a << 5) | (a << 4) | (a << 3) | (a << 2) | (a << 1) | (a);
+ case 2:
+ a = (a << 6) | (a << 4) | (a << 2) | (a);
+ case 3:
+ a = (a << 5) | (a << 2) | (a >> 1);
+ case 4:
+ a = (a << 4) | (a);
+ case 5:
+ a = (a << 3) | (a >> 2);
+ case 6:
+ a = (a << 2) | (a >> 4);
+ case 7:
+ a = (a << 1) | (a >> 6);
+ default:
+ break;
+ }
+ *dataptr = ARGB_JOIN(a, bufptr[2], bufptr[1], bufptr[0]);
+ }
+ else
+ *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
+ dataptr++;
+ bufptr += 4;
+ }
+ break;
+ case 24:
+ for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
+ dataptr++;
+ bufptr += 3;
+ }
+ break;
+ case 16:
+ for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
+ {
+ unsigned char r, g, b, a;
+ unsigned short tmp;
+
+ tmp =
+ (((unsigned short)bufptr[1]) << 8) |
+ (((unsigned short)bufptr[0]));
+ r = (tmp >> 7) & 0xf8; r |= r >> 5;
+ g = (tmp >> 2) & 0xf8; g |= g >> 5;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ a = 0xff;
+ if ((hasa) && (tmp & 0x8000)) a = 0;
+ *dataptr = ARGB_JOIN(a, r, g, b);
+ dataptr++;
+ bufptr += 2;
+ }
+ break;
+ case 8:
+ for (x = 0; (x < w) && ((bufptr + 1) <= bufend); x++)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[0], bufptr[0]);
+ dataptr++;
+ bufptr += 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ int count, i;
+ unsigned char val;
+ unsigned int *dataend;
+
+ dataptr = surface;
+ dataend = dataptr + (w * h);
+ while ((bufptr < bufend) && (dataptr < dataend))
+ {
+ val = *bufptr;
+ bufptr++;
+ count = (val & 0x7f) + 1;
+ if (val & 0x80) // rel packet
+ {
+ switch (bpp)
+ {
+ case 32:
+ if (bufptr < (bufend - 4))
+ {
+ unsigned char r, g, b;
+ int a = bufptr[3];
+
+ switch (abits)
+ {
+ case 1:
+ a = (a << 7) | (a << 6) | (a << 5) | (a << 4) | (a << 3) | (a << 2) | (a << 1) | (a);
+ case 2:
+ a = (a << 6) | (a << 4) | (a << 2) | (a);
+ case 3:
+ a = (a << 5) | (a << 2) | (a >> 1);
+ case 4:
+ a = (a << 4) | (a);
+ case 5:
+ a = (a << 3) | (a >> 2);
+ case 6:
+ a = (a << 2) | (a >> 4);
+ case 7:
+ a = (a << 1) | (a >> 6);
+ default:
+ break;
+ }
+ r = bufptr[2];
+ g = bufptr[1];
+ b = bufptr[0];
+ if (!hasa) a = 0xff;
+ bufptr += 4;
+ for (i = 0; (i < count) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(a, r, g, b);
+ dataptr++;
+ }
+ }
+ break;
+ case 24:
+ if (bufptr < (bufend - 3))
+ {
+ unsigned char r, g, b;
+
+ r = bufptr[2];
+ g = bufptr[1];
+ b = bufptr[0];
+ bufptr += 3;
+ for (i = 0; (i < count) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(0xff, r, g, b);
+ dataptr++;
+ }
+ }
+ break;
+ case 16:
+ if (bufptr < (bufend - 2))
+ {
+ unsigned char r, g, b, a;
+ unsigned short tmp;
+
+ tmp =
+ (((unsigned short)bufptr[1]) << 8) |
+ (((unsigned short)bufptr[0]));
+ r = (tmp >> 7) & 0xf8; r |= r >> 5;
+ g = (tmp >> 2) & 0xf8; g |= g >> 5;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ a = 0xff;
+ if ((hasa) && (tmp & 0x8000)) a = 0;
+ bufptr += 2;
+ for (i = 0; (i < count) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(a, r, g, b);
+ dataptr++;
+ }
+ }
+ break;
+ case 8:
+ if (bufptr < (bufend - 1))
+ {
+ unsigned char g;
+
+ g = bufptr[0];
+ bufptr += 1;
+ for (i = 0; (i < count) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(0xff, g, g, g);
+ dataptr++;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else // raw
+ {
+ switch (bpp)
+ {
+ case 32:
+ for (i = 0; (i < count) && (bufptr < (bufend - 4)) && (dataptr < dataend); i++)
+ {
+ if (hasa)
+// *dataptr = ARGB_JOIN(255 - bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
+ *dataptr = ARGB_JOIN(bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
+ else
+ *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
+ dataptr++;
+ bufptr += 4;
+ }
+ break;
+ case 24:
+ for (i = 0; (i < count) && (bufptr < (bufend - 3)) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
+ dataptr++;
+ bufptr += 3;
+ }
+ break;
+ case 16:
+ for (i = 0; (i < count) && (bufptr < (bufend - 2)) && (dataptr < dataend); i++)
+ {
+ unsigned char r, g, b, a;
+ unsigned short tmp;
+
+ tmp =
+ (((unsigned short)bufptr[1]) << 8) |
+ (((unsigned short)bufptr[0]));
+ r = (tmp >> 7) & 0xf8; r |= r >> 5;
+ g = (tmp >> 2) & 0xf8; g |= g >> 5;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ a = 0xff;
+ if ((hasa) && (tmp & 0x8000)) a = 0;
+ *dataptr = ARGB_JOIN(a, r, g, b);
+ dataptr++;
+ bufptr += 2;
+ }
+ break;
+ case 8:
+ for (i = 0; (i < count) && (bufptr < (bufend - 1)) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[0], bufptr[0]);
+ dataptr++;
+ bufptr += 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (vinverted)
+ {
+ unsigned int *adv, *adv2, tmp;
+
+ adv = surface;
+ adv2 = surface + (w * (h - 1));
+ for (y = 0; y < (h / 2); y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ tmp = adv[x];
+ adv[x] = adv2[x];
+ adv2[x] = tmp;
+ }
+ adv2 -= w;
+ adv += w;
+ }
+ }
+ }
+
+ evas_cserve2_image_premul(ilp);
+
+ eina_file_map_free(f, seg);
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+
+close_file:
+ if (seg != NULL) eina_file_map_free(f, seg);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "tga",
+ evas_image_load_file_head_tga,
+ evas_image_load_file_data_tga
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@evas_image_loader_tiff_cflags@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_TIFF
+#if !EVAS_STATIC_BUILD_TIFF
+
+pkgdir = $(libdir)/evas/cserve2/loaders/tiff/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_tiff.c
+
+module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@ @evas_image_loader_tiff_libs@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_tiff.la
+
+#libevas_loader_tiff_la_SOURCES = evas_image_load_tiff.c
+#libevas_loader_tiff_la_LIBADD = @evas_image_loader_tiff_libs@
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <tiffio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+typedef struct TIFFRGBAImage_Extra TIFFRGBAImage_Extra;
+
+struct TIFFRGBAImage_Extra {
+ TIFFRGBAImage rgba;
+ char pper;
+ uint32 num_pixels;
+ uint32 py;
+};
+
+static Eina_Bool
+evas_image_load_file_head_tiff(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ char txt[1024];
+ TIFFRGBAImage tiff_image;
+ TIFF *tif = NULL;
+ FILE *ffile;
+ int fd;
+ uint16 magic_number;
+
+ ffile = fopen(file, "rb");
+ if (!ffile)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ if (fread(&magic_number, sizeof(uint16), 1, ffile) != 1)
+ {
+ fclose(ffile);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+ /* Apparently rewind(f) isn't sufficient */
+ fseek(ffile, 0, SEEK_SET);
+
+ if ((magic_number != TIFF_BIGENDIAN) /* Checks if actually tiff file */
+ && (magic_number != TIFF_LITTLEENDIAN))
+ {
+ fclose(ffile);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ fd = fileno(ffile);
+ fd = dup(fd);
+ lseek(fd, (long)0, SEEK_SET);
+ fclose(ffile);
+
+ tif = TIFFFdOpen(fd, file, "r");
+ if (!tif)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ strcpy(txt, "Evas Tiff loader: cannot be processed by libtiff");
+ if (!TIFFRGBAImageOK(tif, txt))
+ {
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ strcpy(txt, "Evas Tiff loader: cannot begin reading tiff");
+ if (!TIFFRGBAImageBegin(& tiff_image, tif, 1, txt))
+ {
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ if (tiff_image.alpha != EXTRASAMPLE_UNSPECIFIED)
+ ilp->alpha = 1;
+ if ((tiff_image.width < 1) || (tiff_image.height < 1) ||
+ (tiff_image.width > IMG_MAX_SIZE) || (tiff_image.height > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(tiff_image.width, tiff_image.height))
+ {
+ TIFFClose(tif);
+ if (IMG_TOO_BIG(tiff_image.width, tiff_image.height))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+ ilp->w = tiff_image.width;
+ ilp->h = tiff_image.height;
+
+ TIFFRGBAImageEnd(&tiff_image);
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_tiff(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ char txt[1024];
+ TIFFRGBAImage_Extra rgba_image;
+ TIFF *tif = NULL;
+ FILE *ffile;
+ uint32 *rast = NULL;
+ uint32 num_pixels;
+ int fd, x, y;
+ uint16 magic_number;
+ unsigned int *surface;
+
+ ffile = fopen(file, "rb");
+ if (!ffile)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ if (fread(&magic_number, sizeof(uint16), 1, ffile) != 1)
+ {
+ fclose(ffile);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ /* Apparently rewind(f) isn't sufficient */
+ fseek(ffile, (long)0, SEEK_SET);
+
+ if ((magic_number != TIFF_BIGENDIAN) /* Checks if actually tiff file */
+ && (magic_number != TIFF_LITTLEENDIAN))
+ {
+ fclose(ffile);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ fd = fileno(ffile);
+ fd = dup(fd);
+ lseek(fd, (long)0, SEEK_SET);
+ fclose(ffile);
+
+ tif = TIFFFdOpen(fd, file, "r");
+ if (!tif)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ strcpy(txt, "Evas Tiff loader: cannot be processed by libtiff");
+ if (!TIFFRGBAImageOK(tif, txt))
+ {
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ strcpy(txt, "Evas Tiff loader: cannot begin reading tiff");
+ if (!TIFFRGBAImageBegin((TIFFRGBAImage *) & rgba_image, tif, 0, txt))
+ {
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ if (rgba_image.rgba.alpha != EXTRASAMPLE_UNSPECIFIED)
+ ilp->alpha = 1;
+ if ((rgba_image.rgba.width != ilp->w) ||
+ (rgba_image.rgba.height != ilp->h))
+ {
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ surface = ilp->buffer;
+ if (!surface)
+ {
+ TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ rgba_image.num_pixels = num_pixels = ilp->w * ilp->h;
+
+ rgba_image.pper = rgba_image.py = 0;
+ rast = (uint32 *) _TIFFmalloc(sizeof(uint32) * num_pixels);
+
+ if (!rast)
+ {
+ ERR("Evas Tiff loader: out of memory");
+
+ TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+ if (rgba_image.rgba.bitspersample == 8)
+ {
+ if (!TIFFRGBAImageGet((TIFFRGBAImage *) &rgba_image, rast,
+ rgba_image.rgba.width, rgba_image.rgba.height))
+ {
+ _TIFFfree(rast);
+ TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
+ TIFFClose(tif);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ }
+ /* process rast -> image rgba. really same as prior code anyway just simpler */
+ for (y = 0; y < (int)ilp->h; y++)
+ {
+ DATA32 *pix, *pd;
+ uint32 *ps, pixel;
+ unsigned int a, r, g, b;
+
+ pix = surface;
+ pd = pix + ((ilp->h - y - 1) * ilp->w);
+ ps = rast + (y * ilp->w);
+ for (x = 0; x < (int)ilp->w; x++)
+ {
+ pixel = *ps;
+ a = TIFFGetA(pixel);
+ r = TIFFGetR(pixel);
+ g = TIFFGetG(pixel);
+ b = TIFFGetB(pixel);
+ if (!ilp->alpha) a = 255;
+ if ((rgba_image.rgba.alpha == EXTRASAMPLE_UNASSALPHA) &&
+ (a < 255))
+ {
+ r = (r * (a + 1)) >> 8;
+ g = (g * (a + 1)) >> 8;
+ b = (b * (a + 1)) >> 8;
+ }
+ *pd = ARGB_JOIN(a, r, g, b);
+ ps++;
+ pd++;
+ }
+ }
+
+ _TIFFfree(rast);
+
+ TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
+
+ TIFFClose(tif);
+
+ evas_cserve2_image_alpha_sparse_set(ilp);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "tiff",
+ evas_image_load_file_head_tiff,
+ evas_image_load_file_data_tiff
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_WBMP
+#if !EVAS_STATIC_BUILD_WBMP
+
+pkgdir = $(libdir)/evas/cserve2/loaders/wbmp/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_wbmp.c
+
+module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_wbmp.la
+#libevas_loader_wbmp_la_SOURCES = evas_image_load_wbmp.c
+#libevas_loader_wbmp_la_LIBADD =
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+static int
+read_mb(unsigned int *data, void *map, size_t length, size_t *position)
+{
+ int ac = 0, ct;
+ unsigned char buf;
+
+ for (ct = 0;;)
+ {
+ if ((ct++) == 5) return -1;
+ if (*position > length) return -1;
+ buf = ((unsigned char *) map)[(*position)++];
+ ac = (ac << 7) | (buf & 0x7f);
+ if ((buf & 0x80) == 0) break;
+ }
+ *data = ac;
+ return 0;
+}
+
+static Eina_Bool
+evas_image_load_file_head_wbmp(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ Eina_File *f;
+ void *map = NULL;
+ size_t position = 0;
+ size_t length;
+ unsigned int type, w, h;
+
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ f = eina_file_open(file, 0);
+ if (!f)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ length = eina_file_size_get(f);
+ if (length <= 4) goto bail;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map) goto bail;
+
+ if (read_mb(&type, map, length, &position) < 0) goto bail;
+
+ if (type != 0)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto bail;
+ }
+
+ position++; /* skipping one byte */
+ if (read_mb(&w, map, length, &position) < 0) goto bail;
+ if (read_mb(&h, map, length, &position) < 0) goto bail;
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto bail;
+ }
+
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+ ilp->w = w;
+ ilp->h = h;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+bail:
+ if (map) eina_file_map_free(f, map);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_wbmp(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
+{
+ Eina_File *f;
+ void *map = NULL;
+ size_t position = 0;
+ size_t length;
+ unsigned int type, w, h;
+ unsigned int line_length;
+ unsigned char *line = NULL;
+ int cur = 0, x, y;
+ DATA32 *dst_data;
+
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ f = eina_file_open(file, EINA_FALSE);
+ if (!f)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ length = eina_file_size_get(f);
+ if (length <= 4) goto bail;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map) goto bail;
+
+ if (read_mb(&type, map, length, &position) < 0) goto bail;
+ position++; /* skipping one byte */
+ if (read_mb(&w, map, length, &position) < 0) goto bail;
+ if (read_mb(&h, map, length, &position) < 0) goto bail;
+
+ if (type != 0)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto bail;
+ }
+
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto bail;
+ }
+
+ ilp->w = w;
+ ilp->h = h;
+
+ dst_data = ilp->buffer;
+ if (!dst_data)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto bail;
+ }
+
+ line_length = (ilp->w + 7) >> 3;
+
+ for (y = 0; y < (int)ilp->h; y++)
+ {
+ if (position + line_length > length) goto bail;
+ line = ((unsigned char*) map) + position;
+ position += line_length;
+ for (x = 0; x < (int)ilp->w; x++)
+ {
+ int idx = x >> 3;
+ int offset = 1 << (0x07 - (x & 0x07));
+ if (line[idx] & offset) dst_data[cur] = 0xffffffff;
+ else dst_data[cur] = 0xff000000;
+ cur++;
+ }
+ }
+ eina_file_map_free(f, map);
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+bail:
+ if (map) eina_file_map_free(f, map);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "wbmp",
+ evas_image_load_file_head_wbmp,
+ evas_image_load_file_data_wbmp
+};
+
+static Eina_Bool
+module_init(void)
+{
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
+-I$(top_srcdir)/src/bin \
+@EINA_CFLAGS@ \
+@evas_image_loader_xpm_cflags@ \
+@EVIL_CFLAGS@
+
+if BUILD_LOADER_XPM
+#if !EVAS_STATIC_BUILD_XPM
+pkgdir = $(libdir)/evas/cserve2/loaders/xpm/$(MODULE_ARCH)
+
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_xpm.c
+
+module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@ @evas_image_loader_xpm_libs@
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+
+#else
+
+#noinst_LTLIBRARIES = libevas_loader_xpm.la
+
+#libevas_loader_xpm_la_SOURCES = evas_image_load_xpm.c
+#libevas_loader_xpm_la_LIBADD = @evas_image_loader_xpm_libs@
+
+#endif
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_macros.h"
+
+#include "evas_cserve2.h"
+#include "evas_cserve2_slave.h"
+
+static Eina_File *rgb_txt;
+static void *rgb_txt_map;
+
+static void
+xpm_parse_color(char *color, int *r, int *g, int *b)
+{
+ char *tmp;
+ char *max;
+ char *endline;
+ char buf[4096];
+
+ /* is a #ff00ff like color */
+ if (color[0] == '#')
+ {
+ int len;
+ char val[32];
+
+ len = strlen(color) - 1;
+ if (len < 96)
+ {
+ int i;
+
+ len /= 3;
+ for (i = 0; i < len; i++)
+ val[i] = color[1 + i + (0 * len)];
+ val[i] = 0;
+ sscanf(val, "%x", r);
+ for (i = 0; i < len; i++)
+ val[i] = color[1 + i + (1 * len)];
+ val[i] = 0;
+ sscanf(val, "%x", g);
+ for (i = 0; i < len; i++)
+ val[i] = color[1 + i + (2 * len)];
+ val[i] = 0;
+ sscanf(val, "%x", b);
+ if (len == 1)
+ {
+ *r = (*r << 4) | *r;
+ *g = (*g << 4) | *g;
+ *b = (*b << 4) | *b;
+ }
+ else if (len > 2)
+ {
+ *r >>= (len - 2) * 4;
+ *g >>= (len - 2) * 4;
+ *b >>= (len - 2) * 4;
+ }
+ }
+ return;
+ }
+ /* look in rgb txt database */
+ if (!rgb_txt) return;
+ tmp = rgb_txt_map;
+ max = tmp + eina_file_size_get(rgb_txt);
+
+ while (tmp < max)
+ {
+ endline = memchr(tmp, '\n', max - tmp);
+ if (!endline) endline = max;
+ if ((*tmp != '!') && ((endline - tmp) < (int) (sizeof(buf) - 1)))
+ {
+ int rr, gg, bb;
+ char name[4096];
+
+ /* FIXME: not really efficient */
+ memcpy(buf, tmp, endline - tmp);
+ buf[endline - tmp + 1] = '\0';
+
+ if (sscanf(buf, "%i %i %i %[^\n]", &rr, &gg, &bb, name) == 4)
+ {
+ if (!strcasecmp(name, color))
+ {
+ *r = rr;
+ *g = gg;
+ *b = bb;
+ return;
+ }
+ }
+ }
+ tmp = endline + 1;
+ }
+}
+
+/** FIXME: clean this up and make more efficient **/
+static Eina_Bool
+evas_image_load_file_xpm(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int load_data, int *error)
+{
+ DATA32 *ptr, *end;
+ Eina_File *f;
+ const char *map;
+ size_t length;
+ size_t position;
+
+ int pc, c, i, j, k, w, h, ncolors, cpp, comment, transp,
+ quote, context, len, done, r, g, b, backslash, lu1, lu2;
+ char *line = NULL;
+ char s[256], tok[128], col[256], *tl;
+ int lsz = 256;
+ struct _cmap {
+ char str[6];
+ unsigned char transp;
+ short r, g, b;
+ } *cmap = NULL;
+
+ short lookup[128 - 32][128 - 32];
+ int count, pixels;
+
+ done = 0;
+// transp = -1;
+ transp = 1;
+
+ /* if immediate_load is 1, then dont delay image laoding as below, or */
+ /* already data in this image - dont load it again */
+
+ f = eina_file_open(file, 0);
+ if (!f)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+ length = eina_file_size_get(f);
+ position = 0;
+ if (length < 9)
+ {
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map)
+ {
+ eina_file_close(f);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ if (strncmp("/* XPM */", map, 9))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+
+ i = 0;
+ j = 0;
+ cmap = NULL;
+ w = 10;
+ h = 10;
+ ptr = NULL;
+ end = NULL;
+ c = ' ';
+ comment = 0;
+ quote = 0;
+ context = 0;
+ pixels = 0;
+ count = 0;
+ line = malloc(lsz);
+ if (!line)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+
+ backslash = 0;
+ memset(lookup, 0, sizeof(lookup));
+ while (!done)
+ {
+ pc = c;
+ if (position == length) break ;
+ c = (char) map[position++];
+ if (!quote)
+ {
+ if ((pc == '/') && (c == '*'))
+ comment = 1;
+ else if ((pc == '*') && (c == '/') && (comment))
+ comment = 0;
+ }
+ if (!comment)
+ {
+ if ((!quote) && (c == '"'))
+ {
+ quote = 1;
+ i = 0;
+ }
+ else if ((quote) && (c == '"'))
+ {
+ line[i] = 0;
+ quote = 0;
+ if (context == 0)
+ {
+ /* Header */
+ if (sscanf(line, "%i %i %i %i", &w, &h, &ncolors, &cpp) != 4)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+ if ((ncolors > 32766) || (ncolors < 1))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+ if ((cpp > 5) || (cpp < 1))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+ if ((w > IMG_MAX_SIZE) || (w < 1))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto on_error;
+ }
+ if ((h > IMG_MAX_SIZE) || (h < 1))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto on_error;
+ }
+ if (IMG_TOO_BIG(w, h))
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+
+ if (!cmap)
+ {
+ cmap = malloc(sizeof(struct _cmap) * ncolors);
+ if (!cmap)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+ }
+ ilp->w = w;
+ ilp->h = h;
+
+ j = 0;
+ context++;
+ }
+ else if (context == 1)
+ {
+ /* Color Table */
+ if (j < ncolors)
+ {
+ int slen;
+ int hascolor, iscolor;
+
+ iscolor = 0;
+ hascolor = 0;
+ tok[0] = 0;
+ col[0] = 0;
+ s[0] = 0;
+ len = strlen(line);
+ strncpy(cmap[j].str, line, cpp);
+ cmap[j].str[cpp] = 0;
+ for (slen = 0; slen < cpp; slen++)
+ {
+ /* fix the ascii of the color string - if its < 32 - just limit to 32 */
+ if (cmap[j].str[slen] < 32) cmap[j].str[slen] = 0;
+ }
+ cmap[j].r = -1;
+ cmap[j].transp = 0;
+ for (k = cpp; k < len; k++)
+ {
+ if (line[k] != ' ')
+ {
+ s[0] = 0;
+ sscanf(&line[k], "%255s", s);
+ slen = strlen(s);
+ k += slen;
+ if (!strcmp(s, "c")) iscolor = 1;
+ if ((!strcmp(s, "m")) || (!strcmp(s, "s"))
+ || (!strcmp(s, "g4")) || (!strcmp(s, "g"))
+ || (!strcmp(s, "c")) || (k >= len))
+ {
+ if (k >= len)
+ {
+ if (col[0])
+ {
+ if (strlen(col) < (sizeof(col) - 2))
+ strcat(col, " ");
+ else
+ done = 1;
+ }
+ if ((strlen(col) + strlen(s)) < (sizeof(col) - 1))
+ strcat(col, s);
+ }
+ if (col[0])
+ {
+ if (!strcasecmp(col, "none"))
+ {
+ transp = 1;
+ cmap[j].transp = 1;
+ cmap[j].r = 0;
+ cmap[j].g = 0;
+ cmap[j].b = 0;
+ }
+ else
+ {
+ if ((((cmap[j].r < 0) || (!strcmp(tok, "c"))) && (!hascolor)))
+ {
+ r = g = b = 0;
+ xpm_parse_color(col, &r, &g, &b);
+ cmap[j].r = r;
+ cmap[j].g = g;
+ cmap[j].b = b;
+ if (iscolor) hascolor = 1;
+ }
+ }
+ }
+ strcpy(tok, s);
+ col[0] = 0;
+ }
+ else
+ {
+ if (col[0])
+ {
+ if (strlen(col) < ( sizeof(col) - 2))
+ strcat(col, " ");
+ else
+ done = 1;
+ }
+ if ((strlen(col) + strlen(s)) < (sizeof(col) - 1))
+ strcat(col, s);
+ }
+ }
+ }
+ }
+ j++;
+ if (j >= ncolors)
+ {
+ if (cpp == 1)
+ {
+ for (i = 0; i < ncolors; i++)
+ lookup[(int)cmap[i].str[0] - 32][0] = i;
+ }
+ if (cpp == 2)
+ {
+ for (i = 0; i < ncolors; i++)
+ lookup[(int)cmap[i].str[0] - 32][(int)cmap[i].str[1] - 32] = i;
+ }
+ context++;
+ }
+
+ if (transp) ilp->alpha = 1;
+
+ if (load_data)
+ {
+ ptr = ilp->buffer;
+ if (!ptr)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+ pixels = w * h;
+ end = ptr + pixels;
+ }
+ else
+ {
+ *error = EVAS_LOAD_ERROR_NONE;
+ goto on_success;
+ }
+ }
+ else
+ {
+ /* Image Data */
+ i = 0;
+ if (cpp == 0)
+ {
+ /* Chars per pixel = 0? well u never know */
+ }
+ /* it's xpm - don't care about speed too much. still faster
+ * that most xpm loaders anyway */
+ else if (cpp == 1)
+ {
+ if (transp)
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ lu1 = (int)line[i] - 32;
+ if (lu1 < 0) continue;
+ if (cmap[lookup[lu1][0]].transp)
+ {
+ r = (unsigned char)cmap[lookup[lu1][0]].r;
+ g = (unsigned char)cmap[lookup[lu1][0]].g;
+ b = (unsigned char)cmap[lookup[lu1][0]].b;
+ *ptr = RGB_JOIN(r, g, b);
+ ptr++;
+ count++;
+ }
+ else
+ {
+ r = (unsigned char)cmap[lookup[lu1][0]].r;
+ g = (unsigned char)cmap[lookup[lu1][0]].g;
+ b = (unsigned char)cmap[lookup[lu1][0]].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ lu1 = (int)line[i] - 32;
+ if (lu1 < 0) continue;
+ r = (unsigned char)cmap[lookup[lu1][0]].r;
+ g = (unsigned char)cmap[lookup[lu1][0]].g;
+ b = (unsigned char)cmap[lookup[lu1][0]].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else if (cpp == 2)
+ {
+ if (transp)
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ lu1 = (int)line[i] - 32;
+ i++;
+ lu2 = (int)line[i] - 32;
+ if (lu1 < 0) continue;
+ if (lu2 < 0) continue;
+ if (cmap[lookup[lu1][lu2]].transp)
+ {
+ r = (unsigned char)cmap[lookup[lu1][lu2]].r;
+ g = (unsigned char)cmap[lookup[lu1][lu2]].g;
+ b = (unsigned char)cmap[lookup[lu1][lu2]].b;
+ *ptr = RGB_JOIN(r, g, b);
+ ptr++;
+ count++;
+ }
+ else
+ {
+ r = (unsigned char)cmap[lookup[lu1][lu2]].r;
+ g = (unsigned char)cmap[lookup[lu1][lu2]].g;
+ b = (unsigned char)cmap[lookup[lu1][lu2]].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ lu1 = (int)line[i] - 32;
+ i++;
+ lu2 = (int)line[i] - 32;
+ if (lu1 < 0) continue;
+ if (lu2 < 0) continue;
+ r = (unsigned char)cmap[lookup[lu1][lu2]].r;
+ g = (unsigned char)cmap[lookup[lu1][lu2]].g;
+ b = (unsigned char)cmap[lookup[lu1][lu2]].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else
+ {
+ if (transp)
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ for (j = 0; j < cpp; j++, i++)
+ {
+ col[j] = line[i];
+ if (col[j] < 32) col[j] = 32;
+ }
+ col[j] = 0;
+ i--;
+ for (j = 0; j < ncolors; j++)
+ {
+ if (!strcmp(col, cmap[j].str))
+ {
+ if (cmap[j].transp)
+ {
+ r = (unsigned char)cmap[j].r;
+ g = (unsigned char)cmap[j].g;
+ b = (unsigned char)cmap[j].b;
+ *ptr = RGB_JOIN(r, g, b);
+ ptr++;
+ count++;
+ }
+ else
+ {
+ r = (unsigned char)cmap[j].r;
+ g = (unsigned char)cmap[j].g;
+ b = (unsigned char)cmap[j].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ for (j = 0; j < cpp; j++, i++)
+ {
+ col[j] = line[i];
+ }
+ col[j] = 0;
+ i--;
+ for (j = 0; j < ncolors; j++)
+ {
+ if (!strcmp(col, cmap[j].str))
+ {
+ r = (unsigned char)cmap[j].r;
+ g = (unsigned char)cmap[j].g;
+ b = (unsigned char)cmap[j].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Scan in line from XPM file */
+ if ((!comment) && (quote) && (c != '"'))
+ {
+ if (c < 32) c = 32;
+ else if (c > 127) c = 127;
+ if (c =='\\')
+ {
+ if (++backslash < 2)
+ line[i++] = c;
+ else
+ backslash = 0;
+ }
+ else
+ {
+ backslash = 0;
+ line[i++] = c;
+ }
+ }
+ if (i >= lsz)
+ {
+ lsz += 256;
+ tl = realloc(line, lsz);
+ if (!tl) break;
+ line = tl;
+ }
+ if (((ptr) && ((ptr - (DATA32 *)ilp->buffer) >= (w * h * (int)sizeof(DATA32)))) ||
+ ((context > 1) && (count >= pixels)))
+ break;
+ }
+
+ on_success:
+ free(cmap);
+ free(line);
+
+ eina_file_map_free(f, (void*) map);
+ eina_file_close(f);
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+
+ on_error:
+ free(line);
+ eina_file_map_free(f, (void*) map);
+ eina_file_close(f);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_head_xpm(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
+{
+ return evas_image_load_file_xpm(ilp, file, key, 0, error);
+}
+
+static Eina_Bool
+evas_image_load_file_data_xpm(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
+{
+ return evas_image_load_file_xpm(ilp, file, key, 1, error);
+}
+
+static Evas_Loader_Module_Api modapi =
+{
+ EVAS_CSERVE2_MODULE_API_VERSION,
+ "xpm",
+ evas_image_load_file_head_xpm,
+ evas_image_load_file_data_xpm
+};
+
+static Eina_Bool
+module_init(void)
+{
+ /* Shouldn't we make that PATH configurable ? */
+ rgb_txt = eina_file_open("/usr/lib/X11/rgb.txt", 0);
+ if (!rgb_txt) rgb_txt = eina_file_open("/usr/X11/lib/X11/rgb.txt", 0);
+ if (!rgb_txt) rgb_txt = eina_file_open("/usr/X11R6/lib/X11/rgb.txt", 0);
+ if (!rgb_txt) rgb_txt = eina_file_open("/usr/openwin/lib/X11/rgb.txt", 0);
+ if (rgb_txt)
+ rgb_txt_map = eina_file_map_all(rgb_txt, EINA_FILE_SEQUENTIAL);
+ return evas_cserve2_loader_register(&modapi);
+}
+
+static void
+module_shutdown(void)
+{
+ if (rgb_txt)
+ {
+ eina_file_map_free(rgb_txt, rgb_txt_map);
+ eina_file_close(rgb_txt);
+ rgb_txt = NULL;
+ }
+}
+
+EINA_MODULE_INIT(module_init);
+EINA_MODULE_SHUTDOWN(module_shutdown);
evas_images2_SOURCES = evas-images2.c
evas_images2_LDADD = $(top_builddir)/src/lib/libevas.la @ECORE_EVAS_LIBS@
+examples_PROGRAMS += evas_images3
+evas_images3_SOURCES = evas-images3.c
+evas_images3_LDADD = $(top_builddir)/src/lib/libevas.la @ECORE_EVAS_LIBS@
+
examples_PROGRAMS += evas_text
evas_text_SOURCES = evas-text.c
evas_text_LDADD = $(top_builddir)/src/lib/libevas.la @ECORE_EVAS_LIBS@
$(srcdir)/evas-init-shutdown.c \
$(srcdir)/evas-images.c \
$(srcdir)/evas-images2.c \
+ $(srcdir)/evas-images3.c \
$(srcdir)/evas-object-manipulation.c \
$(srcdir)/evas-events.c \
$(srcdir)/evas-aspect-hints.c \
$(srcdir)/evas-init-shutdown.c \
$(srcdir)/evas-images.c \
$(srcdir)/evas-images2.c \
+ $(srcdir)/evas-images3.c \
$(srcdir)/evas-object-manipulation.c \
$(srcdir)/evas-events.c \
$(srcdir)/evas-aspect-hints.c \
--- /dev/null
+/**
+ * Simple Evas example illustrating some image objects functions
+ *
+ * You'll need at least one engine built for it (excluding the buffer
+ * one) and the png image loader/saver also built. See stdout/stderr
+ * for output.
+ *
+ * @verbatim
+ * gcc -o evas-images2 evas-images2.c `pkg-config --libs --cflags evas ecore ecore-evas`
+ * @endverbatim
+ */
+
+#ifdef HAVE_CONFIG_H
+
+#include "config.h"
+#else
+
+#define PACKAGE_EXAMPLES_DIR "."
+#define __UNUSED__
+
+#endif
+
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define WIDTH (320)
+#define HEIGHT (240)
+
+static const char *img_path = PACKAGE_EXAMPLES_DIR "/enlightenment.png";
+static const char *commands = \
+ "commands are:\n"
+ "\tw - write new pixel data to image\n"
+ "\ti - print image info\n"
+ "\ta - save noise image to disk (/tmp dir)\n"
+ "\th - print help\n";
+
+const char *file_path = "/tmp/evas-images2-example.png";
+const char *quality_str = "quality=100";
+
+struct test_data
+{
+ Ecore_Evas *ee;
+ Evas *evas;
+ Evas_Object *bg;
+ Evas_Object *logo, *logo1;
+};
+
+static struct test_data d = {0};
+
+static void
+_on_destroy(Ecore_Evas *ee __UNUSED__)
+{
+ ecore_main_loop_quit();
+}
+
+/* here just to keep our example's window size and background image's
+ * size in synchrony */
+static void
+_canvas_resize_cb(Ecore_Evas *ee)
+{
+ int w, h;
+
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+ evas_object_resize(d.bg, w, h);
+ evas_object_resize(d.logo, w / 2, h);
+ evas_object_move(d.logo1, w / 2, 0);
+ evas_object_resize(d.logo1, w / 2, h);
+}
+
+static void
+_on_keydown(void *data __UNUSED__,
+ Evas *evas __UNUSED__,
+ Evas_Object *o __UNUSED__,
+ void *einfo)
+{
+ Evas_Event_Key_Down *ev = einfo;
+
+ if (strcmp(ev->keyname, "h") == 0) /* print help */
+ {
+ fprintf(stdout, commands);
+ return;
+ }
+
+ if (strcmp(ev->keyname, "i") == 0) /* change proxy's source */
+ {
+ int stride = evas_object_image_stride_get(d.logo);
+ int w, h;
+
+ evas_object_image_size_get(d.logo, &w, &h);
+
+ printf("image size: %dx%d; stride: %d\n", w, h, stride);
+
+ return;
+ }
+
+ if (strcmp(ev->keyname, "w") == 0) /* save noise image to disk */
+ {
+ int i;
+ char *pixels = evas_object_image_data_get(d.logo, EINA_FALSE);
+ char *bufpixels;
+ int w, h;
+ int stride;
+ Eina_Bool equal = EINA_TRUE;
+
+ evas_object_image_size_get(d.logo, &w, &h);
+ stride = evas_object_image_stride_get(d.logo);
+
+ bufpixels = malloc(sizeof(char) * stride * h);
+ memcpy(bufpixels, pixels, sizeof(char) * stride * h);
+
+ pixels = evas_object_image_data_get(d.logo, EINA_TRUE);
+
+ for (i = 0; i < (stride * h); i++)
+ {
+ if (bufpixels[i] != pixels[i])
+ {
+ equal = EINA_FALSE;
+ break;
+ }
+ }
+
+ free(bufpixels);
+
+ if (!equal)
+ printf("write pixels different from readonly pixels.\n");
+
+ for (i = ((stride * h) / 4) ; i < ((stride * h) / 2) ; i++)
+ {
+ pixels[i] = 0;
+ }
+
+ // evas_object_image_data_set(d.logo, pixels);
+ evas_object_image_data_update_add(d.logo, 0, 0, w, h);
+ return;
+ }
+}
+
+int
+main(void)
+{
+ // unsigned int i;
+ // unsigned int pixels[(WIDTH / 4) * (HEIGHT / 4)];
+
+ if (!ecore_evas_init())
+ return EXIT_FAILURE;
+
+ /* this will give you a window with an Evas canvas under the first
+ * engine available */
+ d.ee = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL);
+ if (!d.ee)
+ goto error;
+
+ ecore_evas_callback_destroy_set(d.ee, _on_destroy);
+ ecore_evas_callback_resize_set(d.ee, _canvas_resize_cb);
+ ecore_evas_show(d.ee);
+
+ /* the canvas pointer, de facto */
+ d.evas = ecore_evas_get(d.ee);
+
+ d.bg = evas_object_rectangle_add(d.evas);
+ evas_object_color_set(d.bg, 255, 255, 255, 255); /* white bg */
+ evas_object_move(d.bg, 0, 0); /* at canvas' origin */
+ evas_object_resize(d.bg, WIDTH, HEIGHT); /* covers full canvas */
+ evas_object_show(d.bg);
+
+ evas_object_focus_set(d.bg, EINA_TRUE);
+ evas_object_event_callback_add(
+ d.bg, EVAS_CALLBACK_KEY_DOWN, _on_keydown, NULL);
+
+ d.logo = evas_object_image_filled_add(d.evas);
+
+ evas_object_image_file_set(d.logo, img_path, NULL);
+ evas_object_resize(d.logo, WIDTH / 2, HEIGHT);
+ evas_object_show(d.logo);
+
+ d.logo1 = evas_object_image_filled_add(d.evas);
+ evas_object_image_file_set(d.logo1, img_path, NULL);
+ evas_object_resize(d.logo1, WIDTH / 2, HEIGHT);
+ evas_object_move(d.logo1, WIDTH / 2, 0);
+ evas_object_show(d.logo1);
+
+ fprintf(stdout, commands);
+ ecore_main_loop_begin();
+
+ ecore_evas_free(d.ee);
+ ecore_evas_shutdown();
+ return 0;
+
+error:
+ fprintf(stderr, "you got to have at least one evas engine built and linked"
+ " up to ecore-evas for this example to run properly.\n");
+ ecore_evas_shutdown();
+ return -1;
+}
MAINTAINERCLEANFILES = Makefile.in
-SUBDIRS = canvas cache cserve file engines include
+SUBDIRS = canvas cache cache2 cserve cserve2 file engines include
EVAS_STATIC_MODULE =
EVAS_STATIC_LIBADD =
endif
+if EVAS_CSERVE2
+
+libevas_cserve2_la = cserve2/libevas_cserve2.la
+
+endif
+
libevas_la_LIBADD = \
canvas/libevas_canvas.la \
file/libevas_file.la \
cache/libevas_cache.la \
$(libevas_cserve_la) \
+$(libevas_cserve2_la) \
engines/common/libevas_engine_common.la \
@FREETYPE_LIBS@ \
@FRIBIDI_LIBS@ \
file/libevas_file.la \
cache/libevas_cache.la \
$(libevas_cserve_la) \
+$(libevas_cserve2_la) \
engines/common/libevas_engine_common.la \
$(EVAS_STATIC_MODULE)
+if EVAS_CSERVE2
+
+libevas_la_LIBADD += \
+cache2/libevas_cache2.la
+
+libevas_la_DEPENDENCIES += \
+cache2/libevas_cache2.la
+
+endif
+
if BUILD_ENGINE_SOFTWARE_16
libevas_la_LIBADD += engines/common_16/libevas_engine_common_16.la
### Evas_GL we are still using it in our code, so just don't install it.
EXTRA_DIST=Evas_GL.h
-DIST_SUBDIRS = canvas cache cserve file engines include
+DIST_SUBDIRS = canvas cache cache2 cserve cserve2 file engines include
//#define CACHEDUMP 1
-#ifdef EVAS_CSERVE
+#ifdef EVAS_CSERVE2
// FIXME: cache server and threaded preload clash badly atm - disable
-//#undef BUILD_ASYNC_PRELOAD
+#undef BUILD_ASYNC_PRELOAD
#endif
#ifdef BUILD_ASYNC_PRELOAD
--- /dev/null
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = -I. \
+ -I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib/include \
+ -I$(top_srcdir)/src/lib/cserve2 \
+ -DPACKAGE_BIN_DIR=\"$(bindir)\" \
+ -DPACKAGE_LIB_DIR=\"$(libdir)\" \
+ -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
+ @EVIL_CFLAGS@ \
+ @FREETYPE_CFLAGS@ \
+ @PIXMAN_CFLAGS@ \
+ @EINA_CFLAGS@ \
+ @PIXMAN_CFLAGS@
+
+if EVAS_CSERVE2
+
+noinst_LTLIBRARIES = libevas_cache2.la
+libevas_cache2_la_SOURCES = \
+evas_cache2.c
+
+noinst_HEADERS = evas_cache2.h
+
+libevas_cache2_la_LIBAD = @EVIL_LIBS@
+
+libevas_cache2_la_DEPENDENCIES = $(top_builddir)/config.h
+
+endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common.h"
+#include "evas_private.h"
+#include "evas_cache2.h"
+#include "evas_cs2.h"
+#include "evas_cs2_private.h"
+
+#define FREESTRC(Var) \
+ if (Var) \
+{ \
+ eina_stringshare_del(Var); \
+ Var = NULL; \
+}
+
+static void _evas_cache_image_dirty_add(Image_Entry *im);
+static void _evas_cache_image_dirty_del(Image_Entry *im);
+static void _evas_cache_image_activ_add(Image_Entry *im);
+static void _evas_cache_image_activ_del(Image_Entry *im);
+static void _evas_cache_image_lru_add(Image_Entry *im);
+static void _evas_cache_image_lru_del(Image_Entry *im);
+static void _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target);
+// static void _evas_cache_image_lru_nodata_add(Image_Entry *im);
+// static void _evas_cache_image_lru_nodata_del(Image_Entry *im);
+
+static void
+_evas_cache_image_dirty_add(Image_Entry *im)
+{
+ if (im->flags.dirty) return;
+ _evas_cache_image_activ_del(im);
+ _evas_cache_image_lru_del(im);
+ // _evas_cache_image_lru_nodata_del(im);
+ im->flags.dirty = 1;
+ im->flags.cached = 1;
+ im->cache2->dirty = eina_inlist_prepend(im->cache2->dirty, EINA_INLIST_GET(im));
+ if (im->cache_key)
+ {
+ eina_stringshare_del(im->cache_key);
+ im->cache_key = NULL;
+ }
+}
+
+static void
+_evas_cache_image_dirty_del(Image_Entry *im)
+{
+ if (!im->flags.dirty) return;
+ if (!im->cache2) return;
+ im->flags.dirty = 0;
+ im->flags.cached = 0;
+ im->cache2->dirty = eina_inlist_remove(im->cache2->dirty, EINA_INLIST_GET(im));
+}
+
+static void
+_evas_cache_image_activ_add(Image_Entry *im)
+{
+ if (im->flags.activ) return;
+ _evas_cache_image_dirty_del(im);
+ _evas_cache_image_lru_del(im);
+ // _evas_cache_image_lru_nodata_del(im);
+ if (!im->cache_key) return;
+ im->flags.activ = 1;
+ im->flags.cached = 1;
+ eina_hash_direct_add(im->cache2->activ, im->cache_key, im);
+}
+
+static void
+_evas_cache_image_activ_del(Image_Entry *im)
+{
+ if (!im->flags.activ) return;
+ if (!im->cache_key) return;
+ im->flags.activ = 0;
+ im->flags.cached = 0;
+ eina_hash_del(im->cache2->activ, im->cache_key, im);
+}
+
+static void
+_evas_cache_image_lru_add(Image_Entry *im)
+{
+ if (im->flags.lru) return;
+ _evas_cache_image_dirty_del(im);
+ _evas_cache_image_activ_del(im);
+ // _evas_cache_image_lru_nodata_del(im);
+ if (!im->cache_key) return;
+ im->flags.lru = 1;
+ im->flags.cached = 1;
+ eina_hash_direct_add(im->cache2->inactiv, im->cache_key, im);
+ im->cache2->lru = eina_inlist_prepend(im->cache2->lru, EINA_INLIST_GET(im));
+ im->cache2->usage += im->cache2->func.mem_size_get(im);
+}
+
+static void
+_evas_cache_image_lru_del(Image_Entry *im)
+{
+ if (!im->flags.lru) return;
+ if (!im->cache_key) return;
+ im->flags.lru = 0;
+ im->flags.cached = 0;
+ eina_hash_del(im->cache2->inactiv, im->cache_key, im);
+ im->cache2->lru = eina_inlist_remove(im->cache2->lru, EINA_INLIST_GET(im));
+ im->cache2->usage -= im->cache2->func.mem_size_get(im);
+}
+
+/*
+static void
+_evas_cache_image_lru_nodata_add(Image_Entry *im)
+{
+ if (im->flags.lru_nodata) return;
+ _evas_cache_image_dirty_del(im);
+ _evas_cache_image_activ_del(im);
+ _evas_cache_image_lru_del(im);
+ im->flags.lru = 1;
+ im->flags.cached = 1;
+ im->cache2->lru_nodata = eina_inlist_prepend(im->cache2->lru_nodata, EINA_INLIST_GET(im));
+}
+
+static void
+_evas_cache_image_lru_nodata_del(Image_Entry *im)
+{
+ if (!im->flags.lru_nodata) return;
+ im->flags.lru = 0;
+ im->flags.cached = 0;
+ im->cache2->lru_nodata = eina_inlist_remove(im->cache2->lru_nodata, EINA_INLIST_GET(im));
+}
+*/
+
+static Eina_Bool
+_timestamp_compare(Image_Timestamp *tstamp, struct stat *st)
+{
+ if (tstamp->mtime != st->st_mtime) return EINA_FALSE;
+ if (tstamp->size != st->st_size) return EINA_FALSE;
+ if (tstamp->ino != st->st_ino) return EINA_FALSE;
+#ifdef _STAT_VER_LINUX
+#if (defined __USE_MISC && defined st_mtime)
+ if (tstamp->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec)
+ return EINA_FALSE;
+#else
+ if (tstamp->mtime_nsec != (unsigned long int)st->st_mtimensec)
+ return EINA_FALSE;
+#endif
+#endif
+ return EINA_TRUE;
+}
+
+static void
+_timestamp_build(Image_Timestamp *tstamp, struct stat *st)
+{
+ tstamp->mtime = st->st_mtime;
+ tstamp->size = st->st_size;
+ tstamp->ino = st->st_ino;
+#ifdef _STAT_VER_LINUX
+#if (defined __USE_MISC && defined st_mtime)
+ tstamp->mtime_nsec = (unsigned long int)st->st_mtim.tv_nsec;
+#else
+ tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec;
+#endif
+#endif
+}
+
+static void
+_evas_cache_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie)
+{
+ if (!ie) return;
+
+ if (ie->flags.delete_me == 1)
+ return;
+
+ if (ie->preload_rid)
+ {
+ ie->flags.delete_me = 1;
+ _evas_cache2_image_entry_preload_remove(ie, NULL);
+ return;
+ }
+
+ _evas_cache_image_dirty_del(ie);
+ _evas_cache_image_activ_del(ie);
+ _evas_cache_image_lru_del(ie);
+ // _evas_cache_image_lru_nodata_del(ie);
+
+
+ if (ie->data1)
+ {
+ evas_cserve2_image_unload(ie);
+ evas_cache2_image_unload_data(ie);
+ evas_cserve2_image_free(ie);
+ }
+ else
+ {
+ if (cache)
+ cache->func.surface_delete(ie);
+ }
+
+ FREESTRC(ie->cache_key);
+ FREESTRC(ie->file);
+ FREESTRC(ie->key);
+ ie->cache2 = NULL;
+
+ evas_common_rgba_image_scalecache_shutdown(ie);
+
+ free(ie);
+}
+
+static Image_Entry *
+_evas_cache_image_entry_new(Evas_Cache2 *cache,
+ const char *hkey,
+ Image_Timestamp *tstamp,
+ const char *file,
+ const char *key,
+ RGBA_Image_Loadopts *lo,
+ int *error)
+{
+ Image_Entry *ie;
+ RGBA_Image *im;
+
+ // ie = cache->func.alloc();
+ im = calloc(1, sizeof(RGBA_Image));
+ if (!im)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ im->flags = RGBA_IMAGE_NOTHING;
+ im->ref = 1;
+ evas_common_rgba_image_scalecache_init(&im->cache_entry);
+
+ ie = &im->cache_entry;
+
+ ie->cache2 = cache;
+ if (hkey) ie->cache_key = eina_stringshare_add(hkey);
+ ie->flags.need_data = 1;
+ ie->space = EVAS_COLORSPACE_ARGB8888;
+ ie->w = -1;
+ ie->h = -1;
+ ie->scale = 1;
+ if (file) ie->file = eina_stringshare_add(file);
+ if (key) ie->key = eina_stringshare_add(key);
+ if (tstamp) ie->tstamp = *tstamp;
+ else memset(&ie->tstamp, 0, sizeof(Image_Timestamp));
+
+ if (lo) ie->load_opts = *lo;
+ if (ie->file)
+ {
+ if (!evas_cserve2_image_load(ie, ie->file, ie->key, &(ie->load_opts)))
+ {
+ ERR("couldn't load '%s' '%s' with cserve2!",
+ ie->file, ie->key ? ie->key : "");
+ _evas_cache_image_entry_delete(cache, ie);
+ return NULL;
+ }
+ }
+
+ if (ie->cache_key) _evas_cache_image_activ_add(ie);
+ else _evas_cache_image_dirty_add(ie);
+ return ie;
+}
+
+EAPI void
+evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h)
+{
+ Evas_Cache2 *cache = ie->cache2;
+ int wmin = w > 0 ? w : 1;
+ int hmin = h > 0 ? h : 1;
+
+ if (cache->func.surface_alloc(ie, wmin, hmin))
+ {
+ wmin = 0;
+ hmin = 0;
+ }
+
+ ie->w = wmin;
+ ie->h = hmin;
+ ie->allocated.w = wmin;
+ ie->allocated.h = hmin;
+ ie->flags.loaded = EINA_TRUE;
+}
+
+static void
+_evas_cache2_image_preloaded_cb(void *data, Eina_Bool success)
+{
+ Image_Entry *ie = data;
+ Evas_Cache_Target *tmp;
+
+ ie->cache2->preload = eina_list_remove(ie->cache2->preload, ie);
+ ie->flags.preload_done = success;
+
+ while ((tmp = ie->targets))
+ {
+ ie->targets = (Evas_Cache_Target *)
+ eina_inlist_remove(EINA_INLIST_GET(ie->targets),
+ EINA_INLIST_GET(ie->targets));
+ if (!ie->flags.delete_me)
+ evas_object_inform_call_image_preloaded((Evas_Object *) tmp->target);
+ free(tmp);
+ }
+
+ if (ie->flags.delete_me)
+ _evas_cache_image_entry_delete(ie->cache2, ie);
+}
+
+static Eina_Bool
+_evas_cache2_image_entry_preload_add(Image_Entry *ie, const void *target)
+{
+ Evas_Cache_Target *tg;
+
+ if (ie->flags.preload_done)
+ return EINA_FALSE;
+
+ tg = malloc(sizeof(Evas_Cache_Target));
+ if (!tg)
+ return EINA_TRUE;
+
+ tg->target = target;
+ ie->targets = (Evas_Cache_Target *)
+ eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
+
+ if (!ie->preload_rid)
+ {
+ ie->cache2->preload = eina_list_append(ie->cache2->preload, ie);
+ evas_cserve2_image_preload(ie, _evas_cache2_image_preloaded_cb);
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target)
+{
+ if (target)
+ {
+ Evas_Cache_Target *tg;
+
+ EINA_INLIST_FOREACH(ie->targets, tg)
+ {
+ if (tg->target == target)
+ {
+ ie->targets = (Evas_Cache_Target *)
+ eina_inlist_remove(EINA_INLIST_GET(ie->targets),
+ EINA_INLIST_GET(tg));
+ free(tg);
+ break;
+ }
+ }
+ }
+ else
+ {
+ Evas_Cache_Target *tg;
+
+ while (ie->targets)
+ {
+ tg = ie->targets;
+ ie->targets = (Evas_Cache_Target *)
+ eina_inlist_remove(EINA_INLIST_GET(ie->targets),
+ EINA_INLIST_GET(tg));
+ free(tg);
+ }
+ }
+
+ // FIXME: Should also send message to the server to cancel the request.
+}
+
+EAPI Image_Entry *
+evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
+{
+ Image_Entry *im;
+
+ if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
+ (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
+ (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
+ w &= ~0x1;
+
+ im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (!im)
+ return NULL;
+
+ im->space = cspace;
+ im->flags.alpha = alpha;
+ evas_cache2_image_surface_alloc(im, w, h);
+ if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
+ {
+ _evas_cache_image_entry_delete(cache, im);
+ return NULL;
+ }
+
+ im->references = 1;
+ im->flags.loaded = EINA_TRUE;
+ if (cache->func.debug) cache->func.debug("copied-data", im);
+
+ return im;
+}
+
+EAPI Image_Entry *
+evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
+{
+ Image_Entry *im;
+
+ if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
+ (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
+ (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
+ w &= ~0x1;
+
+ im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (!im) return NULL;
+ im->w = w;
+ im->h = h;
+ im->flags.alpha = alpha;
+ im->flags.loaded = 1;
+ if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
+ {
+ _evas_cache_image_entry_delete(cache, im);
+ return NULL;
+ }
+ im->references = 1;
+ if (cache->func.debug) cache->func.debug("data", im);
+ return im;
+}
+
+EAPI Image_Entry *
+evas_cache2_image_empty(Evas_Cache2 *cache)
+{
+ Image_Entry *im;
+
+ im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (!im)
+ return NULL;
+
+ im->references = 1;
+ return im;
+}
+
+EAPI Image_Entry *
+evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h)
+{
+ Evas_Cache2 *cache;
+ Image_Entry *im2 = NULL;
+ int error;
+
+ if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
+ (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
+ (im->space == EVAS_COLORSPACE_YCBCR422601_PL))
+ w &= ~0x1;
+
+ if ((im->w == w) && (im->h == h)) return im;
+
+ cache = im->cache2;
+ im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL,
+ NULL);
+ if (!im2) goto on_error;
+
+ im2->flags.alpha = im->flags.alpha;
+ im2->space = im->space;
+ im2->load_opts = im->load_opts;
+ evas_cache2_image_surface_alloc(im2, w, h);
+ error = cache->func.size_set(im2, im, w, h);
+ if (error != 0) goto on_error;
+
+ im2->references = 1;
+
+ evas_cache2_image_close(im);
+ return im2;
+
+on_error:
+ if (im2)
+ _evas_cache_image_entry_delete(cache, im2);
+ return NULL;
+}
+
+EAPI Evas_Cache2 *
+evas_cache2_init(const Evas_Cache2_Image_Func *cb)
+{
+ Evas_Cache2 *cache = calloc(1, sizeof(Evas_Cache2));
+
+ cache->func = *cb;
+ cache->activ = eina_hash_string_superfast_new(NULL);
+ cache->inactiv = eina_hash_string_superfast_new(NULL);
+
+ return cache;
+}
+
+EAPI void
+evas_cache2_shutdown(Evas_Cache2 *cache)
+{
+ eina_hash_free(cache->activ);
+ eina_hash_free(cache->inactiv);
+
+ free(cache);
+}
+
+static void
+_create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, RGBA_Image_Loadopts *lo)
+{
+ const char *ckey = "(null)";
+ size_t size;
+
+ /* generate hkey from file+key+load opts */
+ memcpy(hkey, path, pathlen);
+ size = pathlen;
+ memcpy(hkey + size, "//://", 5);
+ size += 5;
+ if (key) ckey = key;
+ memcpy(hkey + size, ckey, keylen);
+ size += keylen;
+ if (lo)
+ {
+ memcpy(hkey + size, "//@/", 4);
+ size += 4;
+ size += eina_convert_xtoa(lo->scale_down_by, hkey + size);
+ hkey[size] = '/';
+ size += 1;
+ size += eina_convert_dtoa(lo->dpi, hkey + size);
+ hkey[size] = '/';
+ size += 1;
+ size += eina_convert_xtoa(lo->w, hkey + size);
+ hkey[size] = 'x';
+ size += 1;
+ size += eina_convert_xtoa(lo->h, hkey + size);
+ hkey[size] = '/';
+ size += 1;
+ size += eina_convert_xtoa(lo->region.x, hkey + size);
+ hkey[size] = '+';
+ size += 1;
+ size += eina_convert_xtoa(lo->region.y, hkey + size);
+ hkey[size] = '.';
+ size += 1;
+ size += eina_convert_xtoa(lo->region.w, hkey + size);
+ hkey[size] = 'x';
+ size += 1;
+ size += eina_convert_xtoa(lo->region.h, hkey + size);
+
+ if (lo->orientation)
+ {
+ hkey[size] = '/';
+ size += 1;
+ hkey[size] = 'o';
+ size += 1;
+ }
+ }
+ hkey[size] = '\0';
+}
+
+EAPI Image_Entry *
+evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, RGBA_Image_Loadopts *lo, int *error)
+{
+ size_t size;
+ size_t pathlen;
+ size_t keylen;
+ char *hkey;
+ Image_Entry *im;
+ int stat_done = 0, stat_failed = 0;
+ struct stat st;
+ Image_Timestamp tstamp;
+ Evas_Image_Load_Opts prevent = { 0, 0.0, 0, 0, 0, { 0, 0, 0, 0 }, EINA_FALSE };
+
+ if ((!path) || ((!path) && (!key)))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return NULL;
+ }
+
+ pathlen = strlen(path);
+ keylen = key ? strlen(key) : 6;
+ size = pathlen + keylen + 132;
+ hkey = alloca(sizeof(char) * size);
+
+ _create_hash_key(hkey, path, pathlen, key, keylen, lo);
+ DBG("Looking at the hash for key '%s'", hkey);
+
+ /* use local var to copy default load options to the image entry */
+ if ((!lo) ||
+ (lo &&
+ (lo->scale_down_by == 0) &&
+ (lo->dpi == 0.0) &&
+ ((lo->w == 0) || (lo->h == 0)) &&
+ ((lo->region.w == 0) || (lo->region.h == 0)) &&
+ (lo->orientation == 0)
+ ))
+ {
+ lo = &prevent;
+ }
+
+ im = eina_hash_find(cache->activ, hkey);
+
+ if (im)
+ {
+ int ok = 1;
+ DBG("Found entry on active hash for key: '%s'", hkey);
+
+ stat_done = 1;
+ if (stat(path, &st) < 0)
+ {
+ stat_failed = 1;
+ ok = 0;
+ }
+ else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
+ if (ok) goto on_ok;
+ /* image we found doesn't match what's on disk (stat info wise)
+ * so dirty the active cache entry so we never find it again. this
+ * also implicitly guarantees that we only have 1 active copy
+ * of an image at a given key. we wither find it and keep re-reffing
+ * it or we dirty it and get it out */
+ DBG("Entry on inactive hash was invalid (file changed or deleted).");
+ _evas_cache_image_dirty_add(im);
+ im = NULL;
+ }
+
+ im = eina_hash_find(cache->inactiv, hkey);
+
+ if (im)
+ {
+ int ok = 1;
+ DBG("Found entry on inactive hash for key: '%s'", hkey);
+
+ if (!stat_done)
+ {
+ stat_done = 1;
+ if (stat(path, &st) < 0)
+ {
+ stat_failed = 1;
+ ok = 0;
+ }
+ else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
+ }
+ else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
+
+ if (ok)
+ {
+ /* remove from lru and make it active again */
+ _evas_cache_image_lru_del(im);
+ _evas_cache_image_activ_add(im);
+ goto on_ok;
+ }
+ DBG("Entry on inactive hash was invalid (file changed or deleted).");
+ /* as avtive cache find - if we match in lru and its invalid, dirty */
+ _evas_cache_image_dirty_add(im);
+ /* this image never used, so it have to be deleted */
+ _evas_cache_image_entry_delete(cache, im);
+ im = NULL;
+ }
+ if (stat_failed) goto on_stat_error;
+
+ if (!stat_done)
+ {
+ if (stat(path, &st) < 0) goto on_stat_error;
+ }
+ _timestamp_build(&tstamp, &st);
+ DBG("Creating a new entry for key '%s'.", hkey);
+ im = _evas_cache_image_entry_new(cache, hkey, &tstamp, path, key,
+ lo, error);
+ if (!im) goto on_stat_error;
+
+on_ok:
+ *error = EVAS_LOAD_ERROR_NONE;
+ DBG("Using entry on hash for key '%s'", hkey);
+
+ im->references++;
+
+ return im;
+
+on_stat_error:
+#ifndef _WIN32
+ if ((errno == ENOENT) || (errno == ENOTDIR) ||
+ (errno == ENAMETOOLONG) || (errno == ELOOP))
+#else
+ if (errno == ENOENT)
+#endif
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+#ifndef _WIN32
+ else if ((errno == ENOMEM) || (errno == EOVERFLOW))
+#else
+ else if (errno == ENOMEM)
+#endif
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else if (errno == EACCES)
+ *error = EVAS_LOAD_ERROR_PERMISSION_DENIED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+
+ if (im) _evas_cache_image_entry_delete(cache, im);
+ return NULL;
+}
+
+EAPI int
+evas_cache2_image_open_wait(Image_Entry *im)
+{
+ DBG("Wait for open image '%s' '%s'", im->file, im->key);
+ if (evas_cserve2_image_load_wait(im) != CSERVE2_NONE)
+ return EVAS_LOAD_ERROR_GENERIC;
+
+ return EVAS_LOAD_ERROR_NONE;
+}
+
+EAPI void
+evas_cache2_image_close(Image_Entry *im)
+{
+ Evas_Cache2 *cache;
+ int references;
+
+ im->references--;
+ if (im->references < 0)
+ {
+ ERR("image with negative references: %d", im->references);
+ im->references = 0;
+ }
+
+ references = im->references;
+ cache = im->cache2;
+
+ if (references > 0)
+ return;
+
+ if (im->flags.dirty)
+ {
+ _evas_cache_image_entry_delete(cache, im);
+ return;
+ }
+
+ _evas_cache_image_lru_add(im);
+ if (cache)
+ evas_cache2_flush(cache);
+}
+
+EAPI int
+evas_cache2_image_load_data(Image_Entry *ie)
+{
+ int error = EVAS_LOAD_ERROR_NONE;
+
+ if ((ie->flags.loaded) && (!ie->flags.animated))
+ return error;
+
+ ie->flags.in_progress = EINA_TRUE;
+
+ DBG("try cserve2 image data '%s' '%s'",
+ ie->file, ie->key ? ie->key : "");
+ if (evas_cserve2_image_data_load(ie))
+ {
+ evas_cserve2_image_load_data_wait(ie);
+ RGBA_Image *im = (RGBA_Image *)ie;
+ im->image.data = evas_cserve2_image_data_get(ie);
+ DBG("try cserve2 image data '%s' '%s' loaded!",
+ ie->file, ie->key ? ie->key : "");
+ if (im->image.data)
+ {
+ im->image.no_free = 1;
+ error = EVAS_LOAD_ERROR_NONE;
+ }
+ else
+ {
+ ERR("Failed to load data for image '%s' '%s'.",
+ ie->file, ie->key ? ie->key : "");
+ error = EVAS_LOAD_ERROR_GENERIC;
+ }
+ }
+ else
+ {
+ ERR("Couldn't send LOAD message to cserve2.");
+ error = EVAS_LOAD_ERROR_GENERIC;
+ }
+
+ ie->flags.in_progress = EINA_FALSE;
+ ie->flags.loaded = 1;
+
+ if (error != EVAS_LOAD_ERROR_NONE)
+ ie->flags.loaded = 0;
+
+ return error;
+}
+
+EAPI void
+evas_cache2_image_unload_data(Image_Entry *im)
+{
+ // FIXME: This function seems pretty useless, since we always have
+ // to send an UNLOAD message to the server when closing an image,
+ // even if we didn't send a LOAD message before, because the SETOPTS
+ // message increases the image refcount.
+ if (im->flags.in_progress)
+ return;
+
+ if ((!im->file))
+ return;
+
+ if (!im->flags.loaded)
+ return;
+
+// if (im->data2)
+ im->flags.loaded = 0;
+}
+
+EAPI void
+evas_cache2_image_preload_data(Image_Entry *im, const void *target)
+{
+ RGBA_Image *img = (RGBA_Image *)im;
+
+ if ((im->flags.loaded) && (img->image.data))
+ {
+ evas_object_inform_call_image_preloaded((Evas_Object *)target);
+ return;
+ }
+
+ if (!_evas_cache2_image_entry_preload_add(im, target))
+ evas_object_inform_call_image_preloaded((Evas_Object *)target);
+}
+
+EAPI void
+evas_cache2_image_preload_cancel(Image_Entry *im, const void *target)
+{
+ if (!target)
+ return;
+
+ _evas_cache2_image_entry_preload_remove(im, target);
+}
+
+EAPI DATA32 *
+evas_cache2_image_pixels(Image_Entry *im)
+{
+ return im->cache2->func.surface_pixels(im);
+}
+
+EAPI Image_Entry *
+evas_cache2_image_writable(Image_Entry *im)
+{
+ Evas_Cache2 *cache = im->cache2;
+ Image_Entry *im2 = NULL;
+
+ if (!im->cache_key)
+ {
+ if (!im->flags.dirty)
+ _evas_cache_image_dirty_add(im);
+ return im;
+ }
+
+ im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
+ evas_cache2_image_pixels(im),
+ im->flags.alpha, im->space);
+ if (!im2)
+ goto on_error;
+
+ evas_cache2_image_close(im);
+ return im2;
+
+on_error:
+ if (im2)
+ _evas_cache_image_entry_delete(cache, im2);
+ return NULL;
+}
+
+EAPI Image_Entry *
+evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
+{
+ Evas_Cache2 *cache = im->cache2;
+ Image_Entry *im2 = NULL;
+
+ if (!im->cache_key)
+ {
+ if (!im->flags.dirty)
+ _evas_cache_image_dirty_add(im);
+ im2 = im;
+ }
+ else
+ {
+ im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
+ evas_cache2_image_pixels(im),
+ im->flags.alpha, im->space);
+ if (!im2)
+ goto on_error;
+
+ evas_cache2_image_close(im);
+ }
+
+ if (cache->func.dirty_region)
+ cache->func.dirty_region(im2, x, y, w, h);
+
+ return im2;
+
+on_error:
+ if (im2)
+ _evas_cache_image_entry_delete(cache, im2);
+ evas_cache2_image_close(im);
+ return NULL;
+}
+
+EAPI int
+evas_cache2_flush(Evas_Cache2 *cache)
+{
+ if (cache->limit == -1) return -1;
+
+ while ((cache->lru) && (cache->limit < cache->usage))
+ {
+ Image_Entry *im;
+
+ im = (Image_Entry *)cache->lru->last;
+ DBG("Remove unused entry from cache.");
+ _evas_cache_image_entry_delete(cache, im);
+ }
+
+ return cache->usage;
+}
+
+EAPI void
+evas_cache2_limit_set(Evas_Cache2 *cache, int limit)
+{
+ if (cache->limit == limit)
+ return;
+
+ DBG("Cache2 limit set to %d", limit);
+
+ cache->limit = limit;
+
+ evas_cache2_flush(cache);
+}
+
+EAPI int
+evas_cache2_limit_get(Evas_Cache2 *cache)
+{
+ return cache->limit;
+}
+
+EAPI int
+evas_cache2_usage_get(Evas_Cache2 *cache)
+{
+ return cache->usage;
+}
--- /dev/null
+#ifndef _EVAS_CACHE2_H
+#define _EVAS_CACHE2_H
+
+typedef struct _Evas_Cache2_Image_Func Evas_Cache2_Image_Func;
+typedef struct _Evas_Cache2 Evas_Cache2;
+
+struct _Evas_Cache2_Image_Func
+{
+ // Image_Entry *(*alloc)(void);
+ // void (*dealloc)(Image_Entry *im);
+
+ /* The cache provide some helpers for surface manipulation. */
+ int (*surface_alloc)(Image_Entry *im, unsigned int w, unsigned int h);
+ void (*surface_delete)(Image_Entry *im);
+ DATA32 *(*surface_pixels)(Image_Entry *im);
+
+ /* The cache is doing the allocation and deallocation, you must just do the rest. */
+ // int (*constructor)(Image_Entry *im); /**< return is EVAS_LOAD_ERROR_* or EVAS_LOAD_ERROR_NONE! */
+ // void (*destructor)(Image_Entry *im);
+
+ void (*dirty_region)(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
+ /* Only called when references > 0. Need to provide a fresh copie of im. */
+ /* The destination surface does have a surface, but no allocated pixel data. */
+ int (*dirty)(Image_Entry *dst, const Image_Entry *src);
+ /* Only called when references == 1. We will call drop on `im'. */
+ /* The destination surface does not have any surface. */
+ int (*size_set)(Image_Entry *dst, const Image_Entry *src, unsigned int w, unsigned int h);
+
+ /* The destination surface does not have any surface. */
+ int (*copied_data)(Image_Entry *dst, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace);
+ /* The destination surface does not have any surface. */
+ int (*data)(Image_Entry *dst, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace);
+ int (*color_space)(Image_Entry *dst, int cspace);
+
+ /* This function need to update im->w and im->h. */
+ // int (*load)(Image_Entry *im); /**< return is EVAS_LOAD_ERROR_* or EVAS_LOAD_ERROR_NONE! */
+ int (*mem_size_get)(Image_Entry *im);
+ void (*debug)(const char *context, Image_Entry *im);
+};
+
+struct _Evas_Cache2
+{
+ Evas_Cache2_Image_Func func;
+
+ Eina_List *preload;
+
+ Eina_Hash *inactiv;
+ Eina_Hash *activ;
+ Eina_Inlist *dirty;
+ Eina_Inlist *lru;
+ int usage;
+ int limit;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EAPI Evas_Cache2* evas_cache2_init(const Evas_Cache2_Image_Func *cb);
+EAPI void evas_cache2_shutdown(Evas_Cache2 *cache);
+EAPI Image_Entry * evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, RGBA_Image_Loadopts *lo, int *error);
+EAPI int evas_cache2_image_open_wait(Image_Entry *im);
+EAPI void evas_cache2_image_close(Image_Entry *im);
+EAPI int evas_cache2_image_load_data(Image_Entry *ie);
+EAPI void evas_cache2_image_unload_data(Image_Entry *im);
+EAPI void evas_cache2_image_preload_data(Image_Entry *im, const void *target);
+
+EAPI DATA32 * evas_cache2_image_pixels(Image_Entry *im);
+EAPI Image_Entry * evas_cache2_image_writable(Image_Entry *im);
+EAPI Image_Entry * evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace);
+EAPI Image_Entry * evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace);
+EAPI Image_Entry * evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h);
+EAPI Image_Entry * evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
+EAPI Image_Entry * evas_cache2_image_empty(Evas_Cache2 *cache);
+EAPI void evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h);
+
+EAPI int evas_cache2_flush(Evas_Cache2 *cache);
+EAPI void evas_cache2_limit_set(Evas_Cache2 *cache, int limit);
+EAPI int evas_cache2_limit_get(Evas_Cache2 *cache);
+EAPI int evas_cache2_usage_get(Evas_Cache2 *cache);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _EVAS_CACHE2_H */
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib/include \
-I$(top_srcdir)/src/lib/cserve \
+-I$(top_srcdir)/src/lib/cserve2 \
-DPACKAGE_BIN_DIR=\"$(bindir)\" \
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
#include "evas_common.h"
#include "evas_private.h"
#include "evas_cs.h"
+#ifdef EVAS_CSERVE2
+#include "evas_cs2_private.h"
+#endif
#ifdef LKDEBUG
EAPI Eina_Bool lockdebug = EINA_FALSE;
#ifdef EVAS_CSERVE
if (getenv("EVAS_CSERVE")) evas_cserve_init();
#endif
+#ifdef EVAS_CSERVE2
+ if (getenv("EVAS_CSERVE2")) evas_cserve2_init();
+#endif
#ifdef BUILD_ASYNC_PRELOAD
_evas_preload_thread_init();
#endif
MAGIC_CHECK_END();
if (!e->changed) return NULL;
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cserve2_dispatch();
+#endif
evas_call_smarts_calculate(e);
RD("[--- RENDER EVAS (size: %ix%i)\n", e->viewport.w, e->viewport.h);
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+@EINA_CFLAGS@ \
+@FREETYPE_CFLAGS@ \
+@FRIBIDI_CFLAGS@ \
+@EET_CFLAGS@ \
+@FONTCONFIG_CFLAGS@ \
+@pthread_cflags@ \
+@PIXMAN_CFLAGS@
+
+if EVAS_CSERVE2
+
+noinst_LTLIBRARIES = libevas_cserve2.la
+
+libevas_cserve2_la_SOURCES = \
+evas_cs2.h \
+evas_cs2_private.h \
+evas_cs2_image_data.c \
+evas_cs2_client.c
+
+libevas_cserve2_la_LIBADD = @EINA_LIBS@
+
+endif
--- /dev/null
+#ifndef EVAS_CS2_H
+#define EVAS_CS2_H 1
+
+#include <Eina.h>
+
+#ifdef EVAS_CSERVE2
+
+typedef enum {
+ CSERVE2_OPEN = 1,
+ CSERVE2_OPENED,
+ CSERVE2_SETOPTS,
+ CSERVE2_SETOPTSED,
+ CSERVE2_LOAD,
+ CSERVE2_LOADED,
+ CSERVE2_PRELOAD,
+ CSERVE2_PRELOADED,
+ CSERVE2_UNLOAD,
+ CSERVE2_CLOSE,
+ CSERVE2_ERROR
+} Message_Type;
+
+typedef enum {
+ CSERVE2_NONE,
+ CSERVE2_GENERIC,
+ CSERVE2_DOES_NOT_EXIST,
+ CSERVE2_PERMISSION_DENIED,
+ CSERVE2_RESOURCE_ALLOCATION_FAILED,
+ CSERVE2_CORRUPT_FILE,
+ CSERVE2_UNKNOWN_FORMAT,
+ CSERVE2_INVALID_COMMAND,
+ CSERVE2_LOADER_DIED,
+ CSERVE2_LOADER_EXEC_ERR,
+ CSERVE2_INVALID_CACHE, // invalid cserve cache entry
+ CSERVE2_FILE_CHANGED,
+ CSERVE2_REQUEST_CANCEL
+} Error_Type;
+
+struct _Msg_Base {
+ int type;
+ unsigned int rid;
+};
+
+typedef struct _Msg_Base Msg_Base;
+
+struct _Msg_Open {
+ Msg_Base base;
+ unsigned int file_id;
+ int path_offset;
+ int key_offset;
+};
+
+struct _Msg_Opened {
+ Msg_Base base;
+ struct {
+ int w, h;
+ int frame_count;
+ int loop_count;
+ int loop_hint; /* include Evas.h? Copy the enum around? */
+ Eina_Bool alpha : 1;
+ } image;
+};
+
+struct _Msg_Setopts {
+ Msg_Base base;
+ unsigned int file_id;
+ unsigned int image_id;
+ struct {
+ double dpi;
+ int w, h;
+ int scale_down;
+ int rx, ry, rw, rh;
+ Eina_Bool orientation;
+ } opts;
+};
+
+struct _Msg_Setoptsed {
+ Msg_Base base;
+};
+
+struct _Msg_Load {
+ Msg_Base base;
+ unsigned int image_id;
+};
+
+struct _Msg_Loaded {
+ Msg_Base base;
+ struct {
+ int mmap_offset;
+ int use_offset;
+ int mmap_size;
+ int image_size;
+ } shm;
+ Eina_Bool alpha_sparse : 1;
+};
+
+struct _Msg_Preload {
+ Msg_Base base;
+ unsigned int image_id;
+};
+
+struct _Msg_Preloaded {
+ Msg_Base base;
+};
+
+struct _Msg_Unload {
+ Msg_Base base;
+ unsigned int image_id;
+};
+
+struct _Msg_Close {
+ Msg_Base base;
+ unsigned int file_id;
+};
+
+struct _Msg_Error {
+ Msg_Base base;
+ int error;
+};
+
+typedef struct _Msg_Open Msg_Open;
+typedef struct _Msg_Opened Msg_Opened;
+typedef struct _Msg_Setopts Msg_Setopts;
+typedef struct _Msg_Setoptsed Msg_Setoptsed;
+typedef struct _Msg_Load Msg_Load;
+typedef struct _Msg_Loaded Msg_Loaded;
+typedef struct _Msg_Preload Msg_Preload;
+typedef struct _Msg_Preloaded Msg_Preloaded;
+typedef struct _Msg_Unload Msg_Unload;
+typedef struct _Msg_Close Msg_Close;
+typedef struct _Msg_Error Msg_Error;
+
+#endif
+#endif
--- /dev/null
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <Eina.h>
+
+#include "evas_cs2.h"
+#include "evas_cs2_private.h"
+
+#ifdef EVAS_CSERVE2
+
+typedef void (*Op_Callback)(void *data, const void *msg);
+
+struct _File_Entry {
+ unsigned int file_id;
+};
+
+struct _Client_Request {
+ Message_Type type;
+ unsigned int rid;
+ Op_Callback cb;
+ void *data;
+};
+
+typedef struct _File_Entry File_Entry;
+typedef struct _Client_Request Client_Request;
+
+static int cserve2_init = 0;
+static int socketfd = -1;
+
+static unsigned int _rid_count = 0;
+static unsigned int _file_id = 0;
+static unsigned int _data_id = 0;
+
+static Eina_List *_requests = NULL;
+
+static struct sockaddr_un socksize;
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX sizeof(socksize.sun_path)
+#endif
+
+static void
+_socket_path_set(char *path)
+{
+ char *env;
+ char buf[UNIX_PATH_MAX];
+
+ env = getenv("EVAS_CSERVE2_SOCKET");
+ if (env && env[0])
+ {
+ strncpy(path, env, UNIX_PATH_MAX - 1);
+ return;
+ }
+
+ env = getenv("XDG_RUNTIME_DIR");
+ if (!env || !env[0])
+ {
+ env = getenv("HOME");
+ if (!env || !env[0])
+ {
+ env = getenv("TMPDIR");
+ if (!env || !env[0])
+ env = "/tmp";
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "%s/evas-cserve2-%x.socket", env, getuid());
+ /* FIXME: check we can actually create this socket */
+ strcpy(path, buf);
+}
+
+static Eina_Bool
+_server_connect(void)
+{
+ int s, len;
+ struct sockaddr_un remote;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ {
+ ERR("socket");
+ return EINA_FALSE;
+ }
+
+ remote.sun_family = AF_UNIX;
+ _socket_path_set(remote.sun_path);
+ len = strlen(remote.sun_path) + sizeof(remote.sun_family);
+ if (connect(s, (struct sockaddr *)&remote, len) == -1)
+ {
+ ERR("connect");
+ return EINA_FALSE;
+ }
+
+ fcntl(s, F_SETFL, O_NONBLOCK);
+
+ socketfd = s;
+
+ DBG("connected to cserve2 server.");
+ return EINA_TRUE;
+}
+
+static void
+_server_disconnect(void)
+{
+ close(socketfd);
+ socketfd = -1;
+}
+
+static void
+_request_answer_add(Message_Type type, unsigned int rid, Op_Callback cb, void *data)
+{
+ Client_Request *cr = calloc(1, sizeof(*cr));
+
+ cr->type = type;
+ cr->rid = rid;
+ cr->cb = cb;
+ cr->data = data;
+
+ _requests = eina_list_append(_requests, cr);
+}
+
+static Eina_Bool
+_server_send(const void *buf, int size, Op_Callback cb, void *data)
+{
+ const Msg_Base *msg;
+ if (send(socketfd, &size, sizeof(size), MSG_NOSIGNAL) == -1)
+ {
+ ERR("Couldn't send message size to server.");
+ return EINA_FALSE;
+ }
+ if (send(socketfd, buf, size, MSG_NOSIGNAL) == -1)
+ {
+ ERR("Couldn't send message body to server.");
+ return EINA_FALSE;
+ }
+
+ msg = buf;
+ switch (msg->type)
+ {
+ case CSERVE2_OPEN:
+ case CSERVE2_SETOPTS:
+ case CSERVE2_LOAD:
+ case CSERVE2_PRELOAD:
+ _request_answer_add(msg->type, msg->rid, cb, data);
+ break;
+ default:
+ break;
+ }
+
+ return EINA_TRUE;
+}
+
+static int sr_size = 0;
+static int sr_got = 0;
+static char *sr_buf = NULL;
+
+static void *
+_server_read(int *size)
+{
+ int n;
+ void *ret;
+
+ if (sr_size)
+ goto get_data;
+
+ n = recv(socketfd, &sr_size, sizeof(sr_size), 0);
+ if (n < 0)
+ return NULL;
+
+ sr_buf = malloc(sr_size);
+
+get_data:
+ n = recv(socketfd, sr_buf + sr_got, sr_size - sr_got, 0);
+ if (n < 0)
+ return NULL;
+
+ sr_got += n;
+ if (sr_got < sr_size)
+ return NULL;
+
+ *size = sr_size;
+ sr_size = 0;
+ sr_got = 0;
+ ret = sr_buf;
+ sr_buf = NULL;
+
+ return ret;
+}
+
+int
+evas_cserve2_init(void)
+{
+ if (cserve2_init++)
+ return cserve2_init;
+
+ DBG("Connecting to cserve2.");
+ if (!_server_connect())
+ {
+ cserve2_init = 0;
+ return 0;
+ }
+
+ return cserve2_init;
+}
+
+int
+evas_cserve2_shutdown(void)
+{
+ if ((--cserve2_init) > 0)
+ return cserve2_init;
+
+ DBG("Disconnecting from cserve2.");
+ _server_disconnect();
+
+ return cserve2_init;
+}
+
+int
+evas_cserve2_use_get(void)
+{
+ return cserve2_init;
+}
+
+static unsigned int
+_next_rid(void)
+{
+ if (!_rid_count)
+ _rid_count++;
+
+ return _rid_count++;
+}
+
+static unsigned int
+_server_dispatch(void)
+{
+ int size;
+ unsigned int rid;
+ Eina_List *l, *l_next;
+ Client_Request *cr;
+ Msg_Base *msg;
+
+ msg = _server_read(&size);
+ if (!msg)
+ return 0;
+
+ EINA_LIST_FOREACH_SAFE(_requests, l, l_next, cr)
+ {
+ if (cr->rid != msg->rid) // dispatch this answer
+ continue;
+
+ _requests = eina_list_remove_list(_requests, l);
+ if (cr->cb)
+ cr->cb(cr->data, msg);
+ free(cr);
+ }
+
+ rid = msg->rid;
+ free(msg);
+
+ return rid;
+}
+
+static void
+_server_dispatch_until(unsigned int rid)
+{
+ Eina_Bool done = EINA_FALSE;
+
+ while (!done)
+ {
+ if (_server_dispatch() == rid)
+ done = EINA_TRUE;
+ }
+}
+
+static void
+_image_opened_cb(void *data, const void *msg_received)
+{
+ const Msg_Base *answer = msg_received;
+ const Msg_Opened *msg = msg_received;
+ Image_Entry *ie = data;
+
+ ie->open_rid = 0;
+
+ if (answer->type == CSERVE2_ERROR)
+ {
+ const Msg_Error *msg_error = msg_received;
+ ERR("Couldn't open image: '%s':'%s'; error: %d",
+ ie->file, ie->key, msg_error->error);
+ free(ie->data1);
+ ie->data1 = NULL;
+ return;
+ }
+
+ ie->w = msg->image.w;
+ ie->h = msg->image.h;
+ ie->flags.alpha = msg->image.alpha;
+ ie->loop_hint = msg->image.loop_hint;
+ ie->loop_count = msg->image.loop_count;
+ ie->frame_count = msg->image.frame_count;
+}
+
+static void
+_image_loaded_cb(void *data, const void *msg_received)
+{
+ const Msg_Base *answer = msg_received;
+ const Msg_Loaded *msg = msg_received;
+ Image_Entry *ie = data;
+ Data_Entry *dentry = ie->data2;
+ const char *shmpath;
+ int fd;
+
+ ie->load_rid = 0;
+
+ if (!ie->data2)
+ return;
+
+ if (answer->type == CSERVE2_ERROR)
+ {
+ const Msg_Error *msg_error = msg_received;
+ ERR("Couldn't load image: '%s':'%s'; error: %d",
+ ie->file, ie->key, msg_error->error);
+ free(ie->data2);
+ ie->data2 = NULL;
+ return;
+ }
+
+ shmpath = ((const char *)msg) + sizeof(*msg);
+
+ // dentry->shm.path = strdup(shmpath);
+ dentry->shm.mmap_offset = msg->shm.mmap_offset;
+ dentry->shm.use_offset = msg->shm.use_offset;
+ dentry->shm.mmap_size = msg->shm.mmap_size;
+ dentry->shm.image_size = msg->shm.image_size;
+
+ fd = shm_open(shmpath, O_RDONLY, S_IRUSR);
+ if (fd < 0)
+ {
+ free(dentry);
+ ie->data2 = NULL;
+ return;
+ }
+
+ dentry->shm.data = mmap(NULL, dentry->shm.mmap_size, PROT_READ,
+ MAP_SHARED, fd, dentry->shm.mmap_offset);
+
+ if (dentry->shm.data == MAP_FAILED)
+ {
+ free(dentry);
+ ie->data2 = NULL;
+ }
+
+ close(fd);
+
+ if (ie->data2)
+ {
+ ie->flags.loaded = EINA_TRUE;
+ ie->flags.alpha_sparse = msg->alpha_sparse;
+ }
+}
+
+static void
+_image_preloaded_cb(void *data, const void *msg_received)
+{
+ const Msg_Base *answer = msg_received;
+ const Msg_Opened *msg = msg_received;
+ Image_Entry *ie = data;
+ Data_Entry *dentry = ie->data2;
+
+ DBG("Received PRELOADED for RID: %d", answer->rid);
+ ie->preload_rid = 0;
+
+ if (answer->type == CSERVE2_ERROR)
+ {
+ const Msg_Error *msg_error = msg_received;
+ ERR("Couldn't preload image: '%s':'%s'; error: %d",
+ ie->file, ie->key, msg_error->error);
+ dentry->preloaded_cb(data, EINA_FALSE);
+ dentry->preloaded_cb = NULL;
+ return;
+ }
+
+ if (dentry && (dentry->preloaded_cb))
+ {
+ dentry->preloaded_cb(data, EINA_TRUE);
+ dentry->preloaded_cb = NULL;
+ }
+}
+
+static const char *
+_build_absolute_path(const char *path, char buf[], int size)
+{
+ char *p;
+ int len;
+
+ if (!path)
+ return NULL;
+
+ p = buf;
+
+ if (path[0] == '/')
+ strncpy(p, path, size);
+ else if (path[0] == '~')
+ {
+ const char *home = getenv("HOME");
+ if (!home)
+ return NULL;
+ strncpy(p, home, size);
+ len = strlen(p);
+ size -= len + 1;
+ p += len;
+ p[0] = '/';
+ p++;
+ strncpy(p, path + 2, size);
+ }
+ else
+ {
+ if (!getcwd(p, size))
+ return NULL;
+ len = strlen(p);
+ size -= len + 1;
+ p += len;
+ p[0] = '/';
+ p++;
+ strncpy(p, path, size);
+ }
+
+ return buf;
+}
+
+static unsigned int
+_image_open_server_send(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
+{
+ int flen, klen;
+ int size;
+ char *buf;
+ char filebuf[PATH_MAX];
+ Msg_Open msg_open;
+ File_Entry *fentry;
+
+ if (cserve2_init == 0)
+ {
+ ERR("Server not initialized.");
+ return 0;
+ }
+
+ if (!key) key = "";
+
+ _build_absolute_path(file, filebuf, sizeof(filebuf));
+
+ fentry = calloc(1, sizeof(*fentry));
+
+ memset(&msg_open, 0, sizeof(msg_open));
+
+ fentry->file_id = ++_file_id;
+ if (fentry->file_id == 0)
+ fentry->file_id = ++_file_id;
+
+ flen = strlen(filebuf) + 1;
+ klen = strlen(key) + 1;
+
+ msg_open.base.rid = _next_rid();
+ msg_open.base.type = CSERVE2_OPEN;
+ msg_open.file_id = fentry->file_id;
+ msg_open.path_offset = 0;
+ msg_open.key_offset = flen;
+
+ size = sizeof(msg_open) + flen + klen;
+ buf = malloc(size);
+ if (!buf) return EINA_FALSE;
+ memcpy(buf, &msg_open, sizeof(msg_open));
+ memcpy(buf + sizeof(msg_open), filebuf, flen);
+ memcpy(buf + sizeof(msg_open) + flen, key, klen);
+
+ if (!_server_send(buf, size, _image_opened_cb, ie))
+ {
+ ERR("Couldn't send message to server.");
+ free(buf);
+ return 0;
+ }
+
+ free(buf);
+ ie->data1 = fentry;
+
+ return msg_open.base.rid;
+}
+
+unsigned int
+_image_setopts_server_send(Image_Entry *ie)
+{
+ File_Entry *fentry;
+ Data_Entry *dentry;
+ Msg_Setopts msg;
+
+ if (cserve2_init == 0)
+ return 0;
+
+ fentry = ie->data1;
+
+ dentry = calloc(1, sizeof(*dentry));
+
+ memset(&msg, 0, sizeof(msg));
+ dentry->image_id = ++_data_id;
+ if (dentry->image_id == 0)
+ dentry->image_id = ++_data_id;
+
+ msg.base.rid = _next_rid();
+ msg.base.type = CSERVE2_SETOPTS;
+ msg.file_id = fentry->file_id;
+ msg.image_id = dentry->image_id;
+
+ if (!_server_send(&msg, sizeof(msg), 0, NULL))
+ return 0;
+
+ ie->data2 = dentry;
+
+ return msg.base.rid;
+}
+
+unsigned int
+_image_load_server_send(Image_Entry *ie)
+{
+ Data_Entry *dentry;
+ Msg_Load msg;
+
+ if (cserve2_init == 0)
+ return 0;
+
+ if (!ie->data1)
+ {
+ ERR("No data for opened file.");
+ return 0;
+ }
+
+ dentry = ie->data2;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.base.rid = _next_rid();
+ msg.base.type = CSERVE2_LOAD;
+ msg.image_id = dentry->image_id;
+
+ if (!_server_send(&msg, sizeof(msg), _image_loaded_cb, ie))
+ return 0;
+
+ return msg.base.rid;
+}
+
+unsigned int
+_image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
+{
+ Data_Entry *dentry;
+ Msg_Preload msg;
+
+ if (cserve2_init == 0)
+ return 0;
+
+ dentry = ie->data2;
+ dentry->preloaded_cb = preloaded_cb;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.base.rid = _next_rid();
+ msg.base.type = CSERVE2_PRELOAD;
+ msg.image_id = dentry->image_id;
+
+ if (!_server_send(&msg, sizeof(msg), _image_preloaded_cb, ie))
+ return 0;
+
+ return msg.base.rid;
+}
+
+unsigned int
+_image_close_server_send(Image_Entry *ie)
+{
+ Msg_Close msg;
+ File_Entry *fentry;
+
+ if (cserve2_init == 0)
+ return 0;
+
+ if (!ie->data1)
+ return 0;
+
+ fentry = ie->data1;
+
+ if (ie->data2)
+ {
+ free(ie->data2);
+ ie->data2 = NULL;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.base.rid = _next_rid();
+ msg.base.type = CSERVE2_CLOSE;
+ msg.file_id = fentry->file_id;
+
+ free(fentry);
+ ie->data1 = NULL;
+
+ if (!_server_send(&msg, sizeof(msg), NULL, NULL))
+ return 0;
+
+ return msg.base.rid;
+}
+
+unsigned int
+_image_unload_server_send(Image_Entry *ie)
+{
+ Msg_Unload msg;
+ Data_Entry *dentry;
+
+ if (cserve2_init == 0)
+ return 0;
+
+ if (!ie->data2)
+ return 0;
+
+ dentry = ie->data2;
+
+ // if (dentry->shm.path)
+ // free(dentry->shm.path);
+ memset(&msg, 0, sizeof(msg));
+ msg.base.rid = _next_rid();
+ msg.base.type = CSERVE2_UNLOAD;
+ msg.image_id = dentry->image_id;
+
+ free(dentry);
+ ie->data2 = NULL;
+
+ if (!_server_send(&msg, sizeof(msg), NULL, NULL))
+ return 0;
+
+ return msg.base.rid;
+}
+
+Eina_Bool
+evas_cserve2_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
+{
+ unsigned int rid;
+
+ rid = _image_open_server_send(ie, file, key, lopt);
+ if (!rid)
+ return EINA_FALSE;
+
+ ie->open_rid = rid;
+
+ _image_setopts_server_send(ie);
+
+ // _server_dispatch_until(rid);
+
+ if (ie->data1)
+ return EINA_TRUE;
+ else
+ return EINA_FALSE;
+}
+
+int
+evas_cserve2_image_load_wait(Image_Entry *ie)
+{
+ if (ie->open_rid)
+ {
+ _server_dispatch_until(ie->open_rid);
+ if (!ie->data1)
+ return CSERVE2_GENERIC;
+ return CSERVE2_NONE;
+ }
+ else
+ return CSERVE2_GENERIC;
+}
+
+Eina_Bool
+evas_cserve2_image_data_load(Image_Entry *ie)
+{
+ unsigned int rid;
+
+ rid = _image_load_server_send(ie);
+ if (!rid)
+ return EINA_FALSE;
+
+ ie->load_rid = rid;
+
+ if (ie->data2)
+ return EINA_TRUE;
+ else
+ return EINA_FALSE;
+}
+
+void
+evas_cserve2_image_load_data_wait(Image_Entry *ie)
+{
+ if (ie->load_rid)
+ _server_dispatch_until(ie->load_rid);
+}
+
+Eina_Bool
+evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
+{
+ unsigned int rid;
+
+ if (!ie->data1)
+ return EINA_FALSE;
+
+ rid = _image_preload_server_send(ie, preloaded_cb);
+ if (!rid)
+ return EINA_FALSE;
+
+ ie->preload_rid = rid;
+
+ return EINA_FALSE;
+}
+
+void
+evas_cserve2_image_free(Image_Entry *ie)
+{
+ if (!ie->data1)
+ return;
+
+ if (!_image_close_server_send(ie))
+ WRN("Couldn't send close message to cserve2.");
+}
+
+void
+evas_cserve2_image_unload(Image_Entry *ie)
+{
+ if (!ie->data2)
+ return;
+
+ if (!_image_unload_server_send(ie))
+ WRN("Couldn't send unload message to cserve2.");
+}
+
+void
+evas_cserve2_dispatch(void)
+{
+ _server_dispatch_until(0);
+}
+#endif
--- /dev/null
+#include "config.h"
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "evas_cs2.h"
+#include "evas_cs2_private.h"
+
+#ifdef EVAS_CSERVE2
+
+void *
+evas_cserve2_image_data_get(Image_Entry *ie)
+{
+ Data_Entry *dentry = ie->data2;
+
+ if (!dentry)
+ return NULL;
+
+ return dentry->shm.data;
+}
+
+#endif
--- /dev/null
+#ifndef EVAS_CS2_PRIVATE_H
+#define EVAS_CS2_PRIVATE_H 1
+
+#include "evas_common.h"
+
+struct _Data_Entry {
+ unsigned int image_id;
+ void (*preloaded_cb)(void *, Eina_Bool);
+ struct {
+ const char *path;
+ int mmap_offset;
+ int use_offset;
+ int mmap_size;
+ int image_size;
+ void *data;
+ } shm;
+};
+
+typedef struct _Data_Entry Data_Entry;
+
+int evas_cserve2_init(void);
+int evas_cserve2_shutdown(void);
+EAPI int evas_cserve2_use_get(void);
+Eina_Bool evas_cserve2_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt);
+int evas_cserve2_image_load_wait(Image_Entry *ie);
+Eina_Bool evas_cserve2_image_data_load(Image_Entry *ie);
+void evas_cserve2_image_load_data_wait(Image_Entry *ie);
+void evas_cserve2_image_free(Image_Entry *ie);
+void evas_cserve2_image_unload(Image_Entry *ie);
+Eina_Bool evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success));
+void evas_cserve2_dispatch(void);
+
+void *evas_cserve2_image_data_get(Image_Entry *ie);
+#endif
AM_CPPFLAGS = -I. \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib/cserve \
+ -I$(top_srcdir)/src/lib/cserve2 \
-I$(top_srcdir)/src/lib/include \
-DPACKAGE_BIN_DIR=\"$(bindir)\" \
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
/* EAPI RGBA_Image *evas_common_image_create (int w, int h); */
EAPI RGBA_Image *evas_common_image_new (unsigned int w, unsigned int h, unsigned int alpha);
EAPI Evas_Cache_Image *evas_common_image_cache_get (void);
+#ifdef EVAS_CSERVE2
+EAPI Evas_Cache2 *evas_common_image_cache2_get (void);
+#endif
EAPI void evas_common_image_set_cache (unsigned int size);
EAPI int evas_common_image_get_cache (void);
EAPI RGBA_Image *evas_common_load_image_from_file (const char *file, const char *key, RGBA_Image_Loadopts *lo, int *error);
EAPI int evas_common_save_image_to_file (RGBA_Image *im, const char *file, const char *key, int quality, int compress);
+EAPI void evas_common_rgba_image_scalecache_init(Image_Entry *ie);
+EAPI void evas_common_rgba_image_scalecache_shutdown(Image_Entry *ie);
EAPI void evas_common_rgba_image_scalecache_size_set(unsigned int size);
EAPI unsigned int evas_common_rgba_image_scalecache_size_get(void);
EAPI void evas_common_rgba_image_scalecache_flush(void);
#include "evas_common.h"
#include "evas_private.h"
#include "evas_cs.h"
+#ifdef EVAS_CSERVE2
+#include "evas_cs2_private.h"
+#endif
struct ext_loader_s
{
}
}
#endif
+
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ ERR("This function shouldn't be called anymore!");
+ // DBG("try cserve2 '%s' '%s'", ie->file, ie->key ? ie->key : "");
+ // if (evas_cserve2_image_load(ie, ie->file, ie->key, &(ie->load_opts)))
+ // {
+ // DBG("try cserve2 '%s' '%s' loaded!",
+ // ie->file, ie->key ? ie->key : "");
+ // return EVAS_LOAD_ERROR_NONE;
+ // }
+ }
+#endif
if (stat(ie->file, &st) != 0 || S_ISDIR(st.st_mode))
{
DBG("trying to open directory '%s' !", ie->file);
}
#endif
+#ifdef EVAS_CSERVE2
+ if (ie->data1)
+ {
+ ERR("This function shouldn't be called anymore!");
+ // DBG("try cserve2 image data '%s' '%s'",
+ // ie->file, ie->key ? ie->key : "");
+ // if (evas_cserve2_image_data_load(ie))
+ // {
+ // RGBA_Image *im = (RGBA_Image *)ie;
+ // im->image.data = evas_cserve2_image_data_get(ie);
+ // DBG("try cserve2 image data '%s' '%s' loaded!",
+ // ie->file, ie->key ? ie->key : "");
+ // if (im->image.data)
+ // {
+ // im->image.no_free = 1;
+ // return EVAS_LOAD_ERROR_NONE;
+ // }
+ // }
+ // return EVAS_LOAD_ERROR_GENERIC;
+ }
+#endif
+
if (!ie->info.module) return EVAS_LOAD_ERROR_GENERIC;
// printf("load data [%p] %s %s\n", ie, ie->file, ie->key);
//#define SURFDBG 1
static Evas_Cache_Image * eci = NULL;
+#ifdef EVAS_CSERVE2
+static Evas_Cache2 * eci2 = NULL;
+#endif
static int reference = 0;
/* static RGBA_Image *evas_rgba_line_buffer = NULL; */
NULL
};
+#ifdef EVAS_CSERVE2
+static const Evas_Cache2_Image_Func _evas_common_image_func2 =
+{
+ // _evas_common_rgba_image_new,
+ // _evas_common_rgba_image_delete,
+ _evas_common_rgba_image_surface_alloc,
+ _evas_common_rgba_image_surface_delete,
+ _evas_common_rgba_image_surface_pixels,
+ // evas_common_load_rgba_image_module_from_file,
+ // _evas_common_rgba_image_unload,
+ NULL, // _evas_common_rgba_image_dirty_region,
+ NULL, // _evas_common_rgba_image_dirty,
+ evas_common_rgba_image_size_set,
+ evas_common_rgba_image_from_copied_data,
+ evas_common_rgba_image_from_data,
+ NULL, // evas_common_rgba_image_colorspace_set,
+ // evas_common_load_rgba_image_data_from_file,
+ _evas_common_rgba_image_ram_usage,
+/* _evas_common_rgba_image_debug */
+ NULL
+};
+#endif
+
EAPI void
evas_common_image_init(void)
{
if (!eci)
eci = evas_cache_image_init(&_evas_common_image_func);
+#ifdef EVAS_CSERVE2
+ if (!eci2)
+ eci2 = evas_cache2_init(&_evas_common_image_func2);
+#endif
reference++;
//// ERR("REF++=%i", reference);
// ENABLE IT AGAIN, hope it is fixed. Gustavo @ January 22nd, 2009.
evas_cache_image_shutdown(eci);
eci = NULL;
+#ifdef EVAS_CSERVE2
+ evas_cache2_shutdown(eci2);
+ eci2 = NULL;
+#endif
}
#ifdef BUILD_LOADER_EET
#ifdef EVAS_CSERVE
if (ie->data1) evas_cserve_image_free(ie);
#endif
+#ifdef EVAS_CSERVE2
+ if (ie->data1)
+ ERR("Shouldn't reach this point since we are using cache2: '%s' '%s'",
+ ie->file, ie->key);
+ // if (ie->data1) evas_cserve2_image_free(ie);
+#endif
/*
* FIXME: This doesn't seem to be needed... But I'm not sure why.
* -- nash
}
#endif
+#ifdef EVAS_CSERVE2
+ if (ie->data1)
+ {
+ ERR("Shouldn't reach this point since we are using cache2.");
+// evas_cserve2_image_unload(ie);
+// im->image.data = NULL;
+// ie->allocated.w = 0;
+// ie->allocated.h = 0;
+// ie->flags.loaded = 0;
+#ifdef BUILD_ASYNC_PRELOAD
+ ie->flags.preload_done = 0;
+#endif
+ return;
+ }
+#endif
+
if (im->image.data && !im->image.no_free)
{
free(im->image.data);
#ifdef EVAS_CSERVE
if (ie->data1) return 0;
#endif
+#ifdef EVAS_CSERVE2
+ if (ie->data1) return 0;
+#endif
if (im->image.no_free) return 0;
if (im->flags & RGBA_IMAGE_ALPHA_ONLY)
else if (ie->data1)
evas_cserve_image_free(ie);
#endif
+// #ifdef EVAS_CSERVE2
+// else if (ie->data1)
+// ERR("Shouldn't reach this point since we are using cache2.");
+// // evas_cserve2_image_free(ie);
+// #endif
im->image.data = NULL;
ie->allocated.w = 0;
#ifdef EVAS_CSERVE
if (ie->data1) evas_cserve_image_free(ie);
#endif
+#ifdef EVAS_CSERVE2
+ // if (ie->data1) evas_cserve2_image_free(ie);
+ if (ie->data1) ERR("Shouldn't reach this point since we are using cache2.");
+#endif
im->flags |= RGBA_IMAGE_IS_DIRTY;
evas_common_rgba_image_scalecache_dirty(&im->cache_entry);
}
#ifdef EVAS_CSERVE
if (ie_src->data1) evas_cserve_image_free((Image_Entry*) ie_src);
#endif
+#ifdef EVAS_CSERVE2
+ // if (ie_src->data1) evas_cserve2_image_free((Image_Entry*) ie_src);
+ if (ie_src->data1) ERR("Shouldn't reach this point since we are using cache2.");
+#endif
return 1;
}
#ifdef EVAS_CSERVE
if (ie_src->data1) evas_cserve_image_free((Image_Entry*) ie_src);
#endif
+#ifdef EVAS_CSERVE2
+ // if (ie_src->data1) evas_cserve2_image_free((Image_Entry*) ie_src);
+ if (ie_src->data1) ERR("Shouldn't reach this point since we are using cache2.");
+#endif
evas_common_image_colorspace_normalize(src);
evas_common_image_colorspace_normalize(dst);
/* evas_common_blit_rectangle(src, dst, 0, 0, src->cache_entry.w, src->cache_entry.h, 0, 0); */
if (im->image.data)
{
-#ifdef EVAS_CSERVE
+#if defined(EVAS_CSERVE)
+ if ((!im->image.no_free) || (ie->data1))
+#elif defined(EVAS_CSERVE2)
if ((!im->image.no_free) || (ie->data1))
#else
if ((!im->image.no_free))
#ifdef EVAS_CSERVE
if (((Image_Entry *)im)->data1) evas_cserve_image_free(&im->cache_entry);
#endif
+#ifdef EVAS_CSERVE2
+ // if (((Image_Entry *)im)->data1) evas_cserve2_image_free(&im->cache_entry);
+ if (((Image_Entry *)im)->data1) ERR("Shouldn't reach this point since we are using cache2.");
+#endif
if (!im->image.no_free)
{
free(im->image.data);
{
if (eci)
evas_cache_image_set(eci, size);
+#ifdef EVAS_CSERVE2
+ if (eci2)
+ evas_cache2_limit_set(eci2, size);
+#endif
}
EAPI int
return eci;
}
+#ifdef EVAS_CSERVE2
+EAPI Evas_Cache2*
+evas_common_image_cache2_get(void)
+{
+ return eci2;
+}
+#endif
+
EAPI RGBA_Image *
evas_common_image_line_buffer_obtain(int len)
{
void evas_common_scalecache_init(void);
void evas_common_scalecache_shutdown(void);
-void evas_common_rgba_image_scalecache_init(Image_Entry *ie);
-void evas_common_rgba_image_scalecache_shutdown(Image_Entry *ie);
void evas_common_rgba_image_scalecache_dirty(Image_Entry *ie);
void evas_common_rgba_image_scalecache_orig_use(Image_Entry *ie);
int evas_common_rgba_image_scalecache_usage_get(Image_Entry *ie);
#include <assert.h>
+#ifdef EVAS_CSERVE2
+#include "evas_cs2_private.h"
+#endif
#include "evas_common.h"
#include "evas_private.h"
#include "evas_image_private.h"
if ((src_region_w == dst_region_w) && (src_region_h == dst_region_h))
{
if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
- evas_cache_image_load_data(&im->cache_entry);
+ {
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_load_data(&im->cache_entry);
+ else
+#endif
+ evas_cache_image_load_data(&im->cache_entry);
+ }
evas_common_image_colorspace_normalize(im);
// noscales++;
if (!sci)
{
if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
- evas_cache_image_load_data(&im->cache_entry);
+ {
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_load_data(&im->cache_entry);
+ else
+#endif
+ evas_cache_image_load_data(&im->cache_entry);
+ }
evas_common_image_colorspace_normalize(im);
// misses++;
evas_common_draw_context_set_render_op(ct, _EVAS_RENDER_COPY);
}
if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
- evas_cache_image_load_data(&im->cache_entry);
+ {
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_load_data(&im->cache_entry);
+ else
+#endif
+ evas_cache_image_load_data(&im->cache_entry);
+ }
evas_common_image_colorspace_normalize(im);
if (im->image.data)
{
#ifdef EVAS_CSERVE
|| (ie->data1)
#endif
+#ifdef EVAS_CSERVE2
+ || (ie->data1)
+#endif
) &&
(im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)))
{
(im->cache.newest_usage / 20)))
{
//FIXME: imagedataunload - inform owners
- evas_common_rgba_image_unload(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_unload_data(&im->cache_entry);
+ else
+#endif
+ evas_common_rgba_image_unload(&im->cache_entry);
}
}
}
else
{
if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
- evas_cache_image_load_data(&im->cache_entry);
+ {
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_load_data(&im->cache_entry);
+ else
+#endif
+ evas_cache_image_load_data(&im->cache_entry);
+ }
evas_common_image_colorspace_normalize(im);
// misses++;
LKU(im->cache.lock);
#else
RGBA_Image *im = (RGBA_Image *)ie;
if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
- evas_cache_image_load_data(&im->cache_entry);
+ {
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_load_data(&im->cache_entry);
+ else
+#endif
+ evas_cache_image_load_data(&im->cache_entry);
+ }
evas_common_image_colorspace_normalize(im);
if (im->image.data)
{
typedef void (*Gfx_Func_Convert) (DATA32 *src, DATA8 *dst, int src_jump, int dst_jump, int w, int h, int dith_x, int dith_y, DATA8 *pal);
#include "../cache/evas_cache.h"
+#ifdef EVAS_CSERVE2
+#include "../cache2/evas_cache2.h"
+#endif
/*****************************************************************************/
EINA_INLIST;
Evas_Cache_Image *cache;
+#ifdef EVAS_CSERVE2
+ Evas_Cache2 *cache2;
+#endif
const char *cache_key;
Image_Entry_Flags flags;
Evas_Image_Scale_Hint scale_hint;
void *data1, *data2;
+#ifdef EVAS_CSERVE2
+ unsigned int open_rid, load_rid, preload_rid;
+#endif
int server_id;
int connect_num;
int channel;
-I. \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
-I$(top_srcdir)/src/modules/engines \
@EINA_CFLAGS@ \
@FREETYPE_CFLAGS@ \
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef EVAS_CSERVE2
+#include "evas_cs2_private.h"
+#endif
+
#include "evas_common.h"
#include "evas_engine.h"
{
if (buf->priv.back_buf)
{
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_close(&buf->priv.back_buf->cache_entry);
+ else
+#endif
evas_cache_image_drop(&buf->priv.back_buf->cache_entry);
}
free(buf);
(buf->dest) && (buf->dest_row_bytes == (buf->w * sizeof(DATA32))))
{
memset(buf->dest, 0, h * buf->dest_row_bytes);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ buf->priv.back_buf = (RGBA_Image *) evas_cache2_image_data(evas_common_image_cache2_get(),
+ w, h,
+ buf->dest,
+ 1, EVAS_COLORSPACE_ARGB8888);
+ else
+#endif
buf->priv.back_buf = (RGBA_Image *) evas_cache_image_data(evas_common_image_cache_get(),
w, h,
buf->dest,
else if ((buf->depth == OUTBUF_DEPTH_RGB_32BPP_888_8888) &&
(buf->dest) && (buf->dest_row_bytes == (buf->w * sizeof(DATA32))))
{
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ buf->priv.back_buf = (RGBA_Image *) evas_cache2_image_data(evas_common_image_cache2_get(),
+ w, h,
+ buf->dest,
+ 0, EVAS_COLORSPACE_ARGB8888);
+ else
+#endif
buf->priv.back_buf = (RGBA_Image *) evas_cache_image_data(evas_common_image_cache_get(),
w, h,
buf->dest,
else
{
*cx = 0; *cy = 0; *cw = w; *ch = h;
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ im = (RGBA_Image *)evas_cache2_image_empty(evas_common_image_cache2_get());
+ else
+#endif
im = (RGBA_Image *) evas_cache_image_empty(evas_common_image_cache_get());
if (im)
{
((buf->depth == OUTBUF_DEPTH_BGRA_32BPP_8888_8888)))
{
im->cache_entry.flags.alpha = 1;
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_size_set(&im->cache_entry, w, h);
+ else
+#endif
im = (RGBA_Image *) evas_cache_image_size_set(&im->cache_entry, w, h);
}
}
void
evas_buffer_outbuf_buf_free_region_for_update(Outbuf *buf, RGBA_Image *update)
{
- if (update != buf->priv.back_buf) evas_cache_image_drop(&update->cache_entry);
+ if (update != buf->priv.back_buf)
+ {
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_close(&update->cache_entry);
+ else
+#endif
+ evas_cache_image_drop(&update->cache_entry);
+ }
}
void
buf->dest = buf->func.switch_buffer(buf->switch_data, buf->dest);
if (buf->priv.back_buf)
{
- evas_cache_image_drop(&buf->priv.back_buf->cache_entry);
- buf->priv.back_buf = (RGBA_Image *) evas_cache_image_data(evas_common_image_cache_get(),
- buf->w, buf->h,
- buf->dest,
- buf->depth == OUTBUF_DEPTH_ARGB_32BPP_8888_8888 ? 1 : 0,
- EVAS_COLORSPACE_ARGB8888);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&buf->priv.back_buf->cache_entry);
+ buf->priv.back_buf = (RGBA_Image *) evas_cache2_image_data(evas_common_image_cache_get(),
+ buf->w, buf->h,
+ buf->dest,
+ buf->depth == OUTBUF_DEPTH_ARGB_32BPP_8888_8888 ? 1 : 0,
+ EVAS_COLORSPACE_ARGB8888);
+ }
+ else
+#endif
+ {
+ evas_cache_image_drop(&buf->priv.back_buf->cache_entry);
+ buf->priv.back_buf = (RGBA_Image *) evas_cache_image_data(evas_common_image_cache_get(),
+ buf->w, buf->h,
+ buf->dest,
+ buf->depth == OUTBUF_DEPTH_ARGB_32BPP_8888_8888 ? 1 : 0,
+ EVAS_COLORSPACE_ARGB8888);
+ }
}
}
}
-I. \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
-I$(top_srcdir)/src/modules/engines \
@EINA_CFLAGS@ \
@FREETYPE_CFLAGS@ \
#include "evas_common.h" /* Also includes international specific stuff */
#include "evas_private.h"
+#ifdef EVAS_CSERVE2
+#include "evas_cs2_private.h"
+#endif
#ifdef HAVE_DLSYM
# include <dlfcn.h> /* dlopen,dlclose,etc */
eng_image_load(void *data __UNUSED__, const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo)
{
*error = EVAS_LOAD_ERROR_NONE;
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ Image_Entry *ie;
+ ie = evas_cache2_image_open(evas_common_image_cache2_get(),
+ file, key, lo, error);
+ if (ie)
+ evas_cache2_image_open_wait(ie);
+
+ return ie;
+ }
+#endif
return evas_common_load_image_from_file(file, key, lo, error);
}
static void *
eng_image_new_from_data(void *data __UNUSED__, int w, int h, DATA32 *image_data, int alpha, int cspace)
{
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ Evas_Cache2 *cache = evas_common_image_cache2_get();
+ return evas_cache2_image_data(cache, w, h, image_data, alpha, cspace);
+ }
+#endif
return evas_cache_image_data(evas_common_image_cache_get(), w, h, image_data, alpha, cspace);
}
static void *
eng_image_new_from_copied_data(void *data __UNUSED__, int w, int h, DATA32 *image_data, int alpha, int cspace)
{
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ Evas_Cache2 *cache = evas_common_image_cache2_get();
+ return evas_cache2_image_copied_data(cache, w, h, image_data, alpha,
+ cspace);
+ }
+#endif
return evas_cache_image_copied_data(evas_common_image_cache_get(), w, h, image_data, alpha, cspace);
}
static void
eng_image_free(void *data __UNUSED__, void *image)
{
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(image);
+ return;
+ }
+#endif
evas_cache_image_drop(image);
}
{
Image_Entry *im = image;
if (!im) return NULL;
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ return evas_cache2_image_size_set(im, w, h);
+#endif
return evas_cache_image_size_set(im, w, h);
}
{
Image_Entry *im = image;
if (!im) return NULL;
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ return evas_cache2_image_dirty(im, x, y, w, h);
+#endif
return evas_cache_image_dirty(im, x, y, w, h);
}
eng_image_data_get(void *data __UNUSED__, void *image, int to_write, DATA32 **image_data, int *err)
{
RGBA_Image *im;
- int error;
+ int error = EVAS_LOAD_ERROR_NONE;
if (!image)
{
return NULL;
}
im = image;
+
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ error = evas_cache2_image_load_data(&im->cache_entry);
+ if (err) *err = error;
+
+ if (to_write)
+ im = evas_cache2_image_writable(&im->cache_entry);
+
+ *image_data = im->image.data;
+ return im;
+ }
+#endif
+
error = evas_cache_image_load_data(&im->cache_entry);
switch (im->cache_entry.space)
{
im2 = eng_image_new_from_data(data, w, h, image_data,
eng_image_alpha_get(data, image),
eng_image_colorspace_get(data, image));
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ im = im2;
+ break;
+ }
+#endif
evas_cache_image_drop(&im->cache_entry);
im = im2;
}
eng_image_data_preload_request(void *data __UNUSED__, void *image, const void *target)
{
RGBA_Image *im = image;
-
if (!im) return ;
+
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_preload_data(&im->cache_entry, target);
+ return;
+ }
+#endif
evas_cache_image_preload_data(&im->cache_entry, target);
}
eng_image_data_preload_cancel(void *data __UNUSED__, void *image, const void *target)
{
RGBA_Image *im = image;
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ return;
+#endif
if (!im) return ;
evas_cache_image_preload_cancel(&im->cache_entry, target);
#ifdef BUILD_PIPE_RENDER
if ((cpunum > 1))
{
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_load_data(&im->cache_entry);
+#endif
evas_common_rgba_image_scalecache_prepare((Image_Entry *)(im),
surface, context, smooth,
src_x, src_y, src_w, src_h,
else
#endif
{
-// if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
-// evas_cache_image_load_data(&im->cache_entry);
-// evas_common_image_colorspace_normalize(im);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_load_data(&im->cache_entry);
+ goto image_loaded;
+ }
+#endif
+ if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
+ evas_cache_image_load_data(&im->cache_entry);
+ evas_common_image_colorspace_normalize(im);
+
+image_loaded:
evas_common_rgba_image_scalecache_prepare(&im->cache_entry, surface, context, smooth,
src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h);
static void
eng_image_map_surface_free(void *data __UNUSED__, void *surface)
{
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_unload_data(surface);
+ return;
+ }
+#endif
evas_cache_image_drop(surface);
}
-I. \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/lib/cserve2 \
-I$(top_srcdir)/src/modules/engines \
@FREETYPE_CFLAGS@ \
@PIXMAN_CFLAGS@ \
#include <sys/time.h>
#include <sys/utsname.h>
+#ifdef EVAS_CSERVE2
+#include "evas_cs2_private.h"
+#endif
#include "evas_common.h"
#include "evas_macros.h"
#include "evas_xlib_outbuf.h"
im = buf->priv.pending_writes->data;
buf->priv.pending_writes = eina_list_remove_list(buf->priv.pending_writes, buf->priv.pending_writes);
obr = im->extended_info;
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
if (obr->xob) _unfind_xob(obr->xob, 0);
if (obr->mxob) _unfind_xob(obr->mxob, 0);
free(obr);
free(obr);
return NULL;
}
- im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
- buf->w, buf->h,
- (DATA32 *) evas_software_xlib_x_output_buffer_data(obr->xob, &bpl),
- alpha, EVAS_COLORSPACE_ARGB8888);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ im = (RGBA_Image *)evas_cache2_image_data(evas_common_image_cache2_get(),
+ buf->w, buf->h,
+ (DATA32 *) evas_software_xlib_x_output_buffer_data(obr->xob, &bpl),
+ alpha, EVAS_COLORSPACE_ARGB8888);
+ }
+ else
+#endif
+ im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
+ buf->w, buf->h,
+ (DATA32 *) evas_software_xlib_x_output_buffer_data(obr->xob, &bpl),
+ alpha, EVAS_COLORSPACE_ARGB8888);
if (!im)
{
evas_software_xlib_x_output_buffer_free(obr->xob, 0);
}
else
{
- im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ im = (RGBA_Image *)evas_cache2_image_empty(evas_common_image_cache2_get());
+ else
+#endif
+ im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
if (!im)
{
free(obr);
return NULL;
}
im->cache_entry.flags.alpha |= alpha ? 1 : 0;
- evas_cache_image_surface_alloc(&im->cache_entry, buf->w, buf->h);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_surface_alloc(&im->cache_entry, buf->w, buf->h);
+ else
+#endif
+ evas_cache_image_surface_alloc(&im->cache_entry, buf->w, buf->h);
im->extended_info = obr;
if ((buf->rot == 0) || (buf->rot == 180))
{
NULL);
if (!obr->xob)
{
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
free(obr);
return NULL;
}
NULL);
if (!obr->xob)
{
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
free(obr);
return NULL;
}
free(obr);
return NULL;
}
- im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
- w, h,
- (DATA32 *) evas_software_xlib_x_output_buffer_data(obr->xob, &bpl),
- alpha, EVAS_COLORSPACE_ARGB8888);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ im = (RGBA_Image *)evas_cache2_image_data(evas_common_image_cache2_get(),
+ w, h,
+ (DATA32 *) evas_software_xlib_x_output_buffer_data(obr->xob, &bpl),
+ alpha, EVAS_COLORSPACE_ARGB8888);
+ else
+#endif
+ im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
+ w, h,
+ (DATA32 *) evas_software_xlib_x_output_buffer_data(obr->xob, &bpl),
+ alpha, EVAS_COLORSPACE_ARGB8888);
if (!im)
{
_unfind_xob(obr->xob, 0);
}
else
{
- im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ im = (RGBA_Image *)evas_cache2_image_empty(evas_common_image_cache2_get());
+ else
+#endif
+ im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
if (!im)
{
free(obr);
im->cache_entry.w = w;
im->cache_entry.h = h;
im->cache_entry.flags.alpha |= alpha ? 1 : 0;
- evas_cache_image_surface_alloc(&im->cache_entry, w, h);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ evas_cache2_image_surface_alloc(&im->cache_entry, w, h);
+ else
+#endif
+ evas_cache_image_surface_alloc(&im->cache_entry, w, h);
im->extended_info = obr;
if ((buf->rot == 0) || (buf->rot == 180))
{
NULL);
if (!obr->xob)
{
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
free(obr);
return NULL;
}
NULL);
if (!obr->xob)
{
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
free(obr);
return NULL;
}
eina_list_remove_list(buf->priv.prev_pending_writes,
buf->priv.prev_pending_writes);
obr = im->extended_info;
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
if (obr->xob) _unfind_xob(obr->xob, 0);
if (obr->mxob) _unfind_xob(obr->mxob, 0);
free(obr);
im = eina_list_data_get(buf->priv.pending_writes);
buf->priv.pending_writes = eina_list_remove_list(buf->priv.pending_writes, buf->priv.pending_writes);
obr = im->extended_info;
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
if (obr->xob) _unfind_xob(obr->xob, 0);
if (obr->mxob) _unfind_xob(obr->mxob, 0);
free(obr);
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
}
#endif
}
if (obr->xob) evas_software_xlib_x_output_buffer_free(obr->xob, 0);
if (obr->mxob) evas_software_xlib_x_output_buffer_free(obr->mxob, 0);
free(obr);
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
}
else
{
eina_list_remove_list(buf->priv.prev_pending_writes,
buf->priv.prev_pending_writes);
obr = im->extended_info;
- evas_cache_image_drop(&im->cache_entry);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ {
+ evas_cache2_image_close(&im->cache_entry);
+ }
+ else
+#endif
+ evas_cache_image_drop(&im->cache_entry);
if (obr->xob) _unfind_xob(obr->xob, 0);
if (obr->mxob) _unfind_xob(obr->mxob, 0);
free(obr);