diff --git a/legacy/evas/.gitignore b/legacy/evas/.gitignore index da31c37ef4..836f7d1644 100644 --- a/legacy/evas/.gitignore +++ b/legacy/evas/.gitignore @@ -41,6 +41,10 @@ m4/ltversion.m4 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 diff --git a/legacy/evas/AUTHORS b/legacy/evas/AUTHORS index 2aa1185a65..9cad460025 100644 --- a/legacy/evas/AUTHORS +++ b/legacy/evas/AUTHORS @@ -34,3 +34,4 @@ Nicolas Aguirre Rafal Krypa Hyoyoung Chang Jérôme Pinot +Rafael Antognolli diff --git a/legacy/evas/ChangeLog b/legacy/evas/ChangeLog index 4246cc0e36..f6ddb7a831 100644 --- a/legacy/evas/ChangeLog +++ b/legacy/evas/ChangeLog @@ -725,3 +725,9 @@ * 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. diff --git a/legacy/evas/configure.ac b/legacy/evas/configure.ac index eff95cec3e..911d31c330 100644 --- a/legacy/evas/configure.ac +++ b/legacy/evas/configure.ac @@ -92,6 +92,7 @@ want_fribidi="auto" 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" @@ -605,14 +606,34 @@ AC_ARG_ENABLE([evas-cserve], 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]) @@ -622,6 +643,12 @@ fi 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"]) + ####################################### @@ -1865,11 +1892,25 @@ doc/Makefile 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 @@ -2044,6 +2085,7 @@ echo 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 diff --git a/legacy/evas/src/bin/Makefile.am b/legacy/evas/src/bin/Makefile.am index 7159eaa9f8..0abb3bbe51 100644 --- a/legacy/evas/src/bin/Makefile.am +++ b/legacy/evas/src/bin/Makefile.am @@ -39,3 +39,53 @@ $(top_builddir)/src/lib/libevas.la \ @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 diff --git a/legacy/evas/src/bin/dummy_slave.c b/legacy/evas/src/bin/dummy_slave.c new file mode 100644 index 0000000000..a150d67e1f --- /dev/null +++ b/legacy/evas/src/bin/dummy_slave.c @@ -0,0 +1,205 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/legacy/evas/src/bin/evas_cserve2.h b/legacy/evas/src/bin/evas_cserve2.h new file mode 100644 index 0000000000..92cfe627ed --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2.h @@ -0,0 +1,180 @@ +#ifndef _EVAS_CSERVE2_H +#define _EVAS_CSERVE2_H + +#include +#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 */ diff --git a/legacy/evas/src/bin/evas_cserve2_cache.c b/legacy/evas/src/bin/evas_cserve2_cache.c new file mode 100644 index 0000000000..3cd45474ed --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_cache.c @@ -0,0 +1,1261 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#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); +} diff --git a/legacy/evas/src/bin/evas_cserve2_client.c b/legacy/evas/src/bin/evas_cserve2_client.c new file mode 100644 index 0000000000..9863dc8f5a --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_client.c @@ -0,0 +1,429 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/legacy/evas/src/bin/evas_cserve2_main.c b/legacy/evas/src/bin/evas_cserve2_main.c new file mode 100644 index 0000000000..47f120e5e2 --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_main.c @@ -0,0 +1,456 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#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); +} diff --git a/legacy/evas/src/bin/evas_cserve2_main_loop_linux.c b/legacy/evas/src/bin/evas_cserve2_main_loop_linux.c new file mode 100644 index 0000000000..b092cc2b77 --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_main_loop_linux.c @@ -0,0 +1,779 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "evas_cserve2.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/legacy/evas/src/bin/evas_cserve2_messages.c b/legacy/evas/src/bin/evas_cserve2_messages.c new file mode 100644 index 0000000000..51868969dd --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_messages.c @@ -0,0 +1,189 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#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; +} diff --git a/legacy/evas/src/bin/evas_cserve2_shm.c b/legacy/evas/src/bin/evas_cserve2_shm.c new file mode 100644 index 0000000000..36291f947c --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_shm.c @@ -0,0 +1,147 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "evas_cserve2.h" + +#include +#include +#include +#include +#include + +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; +} diff --git a/legacy/evas/src/bin/evas_cserve2_slave.c b/legacy/evas/src/bin/evas_cserve2_slave.c new file mode 100644 index 0000000000..b6e46101e5 --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_slave.c @@ -0,0 +1,480 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/legacy/evas/src/bin/evas_cserve2_slave.h b/legacy/evas/src/bin/evas_cserve2_slave.h new file mode 100644 index 0000000000..a491b45d8b --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_slave.h @@ -0,0 +1,86 @@ +#ifndef _EVAS_CSERVE2_SLAVE_H +#define _EVAS_CSERVE2_SLAVE_H + +#include + +/* 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 */ diff --git a/legacy/evas/src/bin/evas_cserve2_slaves.c b/legacy/evas/src/bin/evas_cserve2_slaves.c new file mode 100644 index 0000000000..452df0d13e --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_slaves.c @@ -0,0 +1,395 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "evas_cserve2.h" + +#include +#include +#include +#include +#include + +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); +} diff --git a/legacy/evas/src/bin/evas_cserve2_utils.c b/legacy/evas/src/bin/evas_cserve2_utils.c new file mode 100644 index 0000000000..68fa216e19 --- /dev/null +++ b/legacy/evas/src/bin/evas_cserve2_utils.c @@ -0,0 +1,58 @@ +#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; +} diff --git a/legacy/evas/src/bin/loaders/Makefile.am b/legacy/evas/src/bin/loaders/Makefile.am new file mode 100644 index 0000000000..46222c843c --- /dev/null +++ b/legacy/evas/src/bin/loaders/Makefile.am @@ -0,0 +1,47 @@ +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 diff --git a/legacy/evas/src/bin/loaders/bmp/Makefile.am b/legacy/evas/src/bin/loaders/bmp/Makefile.am new file mode 100644 index 0000000000..113c19b94c --- /dev/null +++ b/legacy/evas/src/bin/loaders/bmp/Makefile.am @@ -0,0 +1,32 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/bmp/evas_image_load_bmp.c b/legacy/evas/src/bin/loaders/bmp/evas_image_load_bmp.c new file mode 100644 index 0000000000..4a00547d07 --- /dev/null +++ b/legacy/evas/src/bin/loaders/bmp/evas_image_load_bmp.c @@ -0,0 +1,1479 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifdef HAVE_EVIL +# include +#endif + +#include + +#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); diff --git a/legacy/evas/src/bin/loaders/eet/Makefile.am b/legacy/evas/src/bin/loaders/eet/Makefile.am new file mode 100644 index 0000000000..b6aedfbb23 --- /dev/null +++ b/legacy/evas/src/bin/loaders/eet/Makefile.am @@ -0,0 +1,34 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/eet/evas_image_load_eet.c b/legacy/evas/src/bin/loaders/eet/evas_image_load_eet.c new file mode 100644 index 0000000000..1eee2e7a9f --- /dev/null +++ b/legacy/evas/src/bin/loaders/eet/evas_image_load_eet.c @@ -0,0 +1,158 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" /* so that EAPI in Eet.h is correctly defined */ +#endif + +#include + +#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); diff --git a/legacy/evas/src/bin/loaders/ico/Makefile.am b/legacy/evas/src/bin/loaders/ico/Makefile.am new file mode 100644 index 0000000000..10d0d4e778 --- /dev/null +++ b/legacy/evas/src/bin/loaders/ico/Makefile.am @@ -0,0 +1,32 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/ico/evas_image_load_ico.c b/legacy/evas/src/bin/loaders/ico/evas_image_load_ico.c new file mode 100644 index 0000000000..53c9b52293 --- /dev/null +++ b/legacy/evas/src/bin/loaders/ico/evas_image_load_ico.c @@ -0,0 +1,789 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifdef HAVE_EVIL +# include +#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); diff --git a/legacy/evas/src/bin/loaders/jpeg/Makefile.am b/legacy/evas/src/bin/loaders/jpeg/Makefile.am new file mode 100644 index 0000000000..5bb093fd23 --- /dev/null +++ b/legacy/evas/src/bin/loaders/jpeg/Makefile.am @@ -0,0 +1,33 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/jpeg/evas_image_load_jpeg.c b/legacy/evas/src/bin/loaders/jpeg/evas_image_load_jpeg.c new file mode 100644 index 0000000000..4fbd061f40 --- /dev/null +++ b/legacy/evas/src/bin/loaders/jpeg/evas_image_load_jpeg.c @@ -0,0 +1,1118 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include + +#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); diff --git a/legacy/evas/src/bin/loaders/pmaps/Makefile.am b/legacy/evas/src/bin/loaders/pmaps/Makefile.am new file mode 100644 index 0000000000..16410410ce --- /dev/null +++ b/legacy/evas/src/bin/loaders/pmaps/Makefile.am @@ -0,0 +1,33 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/pmaps/evas_image_load_pmaps.c b/legacy/evas/src/bin/loaders/pmaps/evas_image_load_pmaps.c new file mode 100644 index 0000000000..22a9791a3a --- /dev/null +++ b/legacy/evas/src/bin/loaders/pmaps/evas_image_load_pmaps.c @@ -0,0 +1,573 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include + +#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); diff --git a/legacy/evas/src/bin/loaders/png/Makefile.am b/legacy/evas/src/bin/loaders/png/Makefile.am new file mode 100644 index 0000000000..e99660c16c --- /dev/null +++ b/legacy/evas/src/bin/loaders/png/Makefile.am @@ -0,0 +1,33 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/png/evas_image_load_png.c b/legacy/evas/src/bin/loaders/png/evas_image_load_png.c new file mode 100644 index 0000000000..544fc6bad4 --- /dev/null +++ b/legacy/evas/src/bin/loaders/png/evas_image_load_png.c @@ -0,0 +1,310 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#ifdef HAVE_EVIL +# include +#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); diff --git a/legacy/evas/src/bin/loaders/psd/Makefile.am b/legacy/evas/src/bin/loaders/psd/Makefile.am new file mode 100644 index 0000000000..55a3ab2f66 --- /dev/null +++ b/legacy/evas/src/bin/loaders/psd/Makefile.am @@ -0,0 +1,32 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/psd/evas_image_load_psd.c b/legacy/evas/src/bin/loaders/psd/evas_image_load_psd.c new file mode 100644 index 0000000000..30a31179f6 --- /dev/null +++ b/legacy/evas/src/bin/loaders/psd/evas_image_load_psd.c @@ -0,0 +1,981 @@ +#define _XOPEN_SOURCE + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#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); diff --git a/legacy/evas/src/bin/loaders/tga/Makefile.am b/legacy/evas/src/bin/loaders/tga/Makefile.am new file mode 100644 index 0000000000..7b813caea3 --- /dev/null +++ b/legacy/evas/src/bin/loaders/tga/Makefile.am @@ -0,0 +1,32 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/tga/evas_image_load_tga.c b/legacy/evas/src/bin/loaders/tga/evas_image_load_tga.c new file mode 100644 index 0000000000..4c7d5f1e60 --- /dev/null +++ b/legacy/evas/src/bin/loaders/tga/evas_image_load_tga.c @@ -0,0 +1,574 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#ifdef HAVE_EVIL +# include +#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); diff --git a/legacy/evas/src/bin/loaders/tiff/Makefile.am b/legacy/evas/src/bin/loaders/tiff/Makefile.am new file mode 100644 index 0000000000..19458ebc88 --- /dev/null +++ b/legacy/evas/src/bin/loaders/tiff/Makefile.am @@ -0,0 +1,34 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/tiff/evas_image_load_tiff.c b/legacy/evas/src/bin/loaders/tiff/evas_image_load_tiff.c new file mode 100644 index 0000000000..e48e72f482 --- /dev/null +++ b/legacy/evas/src/bin/loaders/tiff/evas_image_load_tiff.c @@ -0,0 +1,282 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_EVIL +# include +#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); diff --git a/legacy/evas/src/bin/loaders/wbmp/Makefile.am b/legacy/evas/src/bin/loaders/wbmp/Makefile.am new file mode 100644 index 0000000000..b96e17919a --- /dev/null +++ b/legacy/evas/src/bin/loaders/wbmp/Makefile.am @@ -0,0 +1,32 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/wbmp/evas_image_load_wbmp.c b/legacy/evas/src/bin/loaders/wbmp/evas_image_load_wbmp.c new file mode 100644 index 0000000000..6c34aa63d7 --- /dev/null +++ b/legacy/evas/src/bin/loaders/wbmp/evas_image_load_wbmp.c @@ -0,0 +1,189 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifdef HAVE_EVIL +# include +#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); diff --git a/legacy/evas/src/bin/loaders/xpm/Makefile.am b/legacy/evas/src/bin/loaders/xpm/Makefile.am new file mode 100644 index 0000000000..8edae6c426 --- /dev/null +++ b/legacy/evas/src/bin/loaders/xpm/Makefile.am @@ -0,0 +1,34 @@ + +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 diff --git a/legacy/evas/src/bin/loaders/xpm/evas_image_load_xpm.c b/legacy/evas/src/bin/loaders/xpm/evas_image_load_xpm.c new file mode 100644 index 0000000000..8404509c70 --- /dev/null +++ b/legacy/evas/src/bin/loaders/xpm/evas_image_load_xpm.c @@ -0,0 +1,650 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#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); diff --git a/legacy/evas/src/examples/Makefile.am b/legacy/evas/src/examples/Makefile.am index 1bb3f37ab4..757ca54260 100644 --- a/legacy/evas/src/examples/Makefile.am +++ b/legacy/evas/src/examples/Makefile.am @@ -67,6 +67,10 @@ examples_PROGRAMS += evas_images2 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@ @@ -116,6 +120,7 @@ files_DATA += \ $(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 \ @@ -132,6 +137,7 @@ EXTRA_DIST = $(EDCS) \ $(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 \ diff --git a/legacy/evas/src/examples/evas-images3.c b/legacy/evas/src/examples/evas-images3.c new file mode 100644 index 0000000000..5d627b0a37 --- /dev/null +++ b/legacy/evas/src/examples/evas-images3.c @@ -0,0 +1,196 @@ +/** + * 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 +#include +#include +#include + +#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; +} diff --git a/legacy/evas/src/lib/Makefile.am b/legacy/evas/src/lib/Makefile.am index 1240b2bf59..9d9f3a1039 100644 --- a/legacy/evas/src/lib/Makefile.am +++ b/legacy/evas/src/lib/Makefile.am @@ -1,6 +1,6 @@ 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 = @@ -212,11 +212,18 @@ libevas_cserve_la = cserve/libevas_cserve.la 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@ \ @@ -235,9 +242,20 @@ canvas/libevas_canvas.la \ 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 @@ -257,4 +275,4 @@ libevas_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @versio ### 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 diff --git a/legacy/evas/src/lib/cache/evas_cache_image.c b/legacy/evas/src/lib/cache/evas_cache_image.c index 8ebe806091..44a9354b45 100644 --- a/legacy/evas/src/lib/cache/evas_cache_image.c +++ b/legacy/evas/src/lib/cache/evas_cache_image.c @@ -17,9 +17,9 @@ //#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 diff --git a/legacy/evas/src/lib/cache2/Makefile.am b/legacy/evas/src/lib/cache2/Makefile.am new file mode 100644 index 0000000000..24806e3c2e --- /dev/null +++ b/legacy/evas/src/lib/cache2/Makefile.am @@ -0,0 +1,29 @@ + +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 diff --git a/legacy/evas/src/lib/cache2/evas_cache2.c b/legacy/evas/src/lib/cache2/evas_cache2.c new file mode 100644 index 0000000000..8a15b3d5f8 --- /dev/null +++ b/legacy/evas/src/lib/cache2/evas_cache2.c @@ -0,0 +1,932 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_EVIL +# include +#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; +} diff --git a/legacy/evas/src/lib/cache2/evas_cache2.h b/legacy/evas/src/lib/cache2/evas_cache2.h new file mode 100644 index 0000000000..7028338e7b --- /dev/null +++ b/legacy/evas/src/lib/cache2/evas_cache2.h @@ -0,0 +1,87 @@ +#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 */ diff --git a/legacy/evas/src/lib/canvas/Makefile.am b/legacy/evas/src/lib/canvas/Makefile.am index 875107e03c..4e4e83c0d5 100644 --- a/legacy/evas/src/lib/canvas/Makefile.am +++ b/legacy/evas/src/lib/canvas/Makefile.am @@ -5,6 +5,7 @@ AM_CPPFLAGS = \ -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)\" \ diff --git a/legacy/evas/src/lib/canvas/evas_main.c b/legacy/evas/src/lib/canvas/evas_main.c index 309eb98216..b02405d08d 100644 --- a/legacy/evas/src/lib/canvas/evas_main.c +++ b/legacy/evas/src/lib/canvas/evas_main.c @@ -1,6 +1,9 @@ #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; @@ -47,6 +50,9 @@ evas_init(void) #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 diff --git a/legacy/evas/src/lib/canvas/evas_render.c b/legacy/evas/src/lib/canvas/evas_render.c index 460d0fed3d..f9c7f3315c 100644 --- a/legacy/evas/src/lib/canvas/evas_render.c +++ b/legacy/evas/src/lib/canvas/evas_render.c @@ -1366,6 +1366,10 @@ evas_render_updates_internal(Evas *e, 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); diff --git a/legacy/evas/src/lib/cserve2/Makefile.am b/legacy/evas/src/lib/cserve2/Makefile.am new file mode 100644 index 0000000000..252899f721 --- /dev/null +++ b/legacy/evas/src/lib/cserve2/Makefile.am @@ -0,0 +1,27 @@ +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 diff --git a/legacy/evas/src/lib/cserve2/evas_cs2.h b/legacy/evas/src/lib/cserve2/evas_cs2.h new file mode 100644 index 0000000000..a33857f425 --- /dev/null +++ b/legacy/evas/src/lib/cserve2/evas_cs2.h @@ -0,0 +1,133 @@ +#ifndef EVAS_CS2_H +#define EVAS_CS2_H 1 + +#include + +#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 diff --git a/legacy/evas/src/lib/cserve2/evas_cs2_client.c b/legacy/evas/src/lib/cserve2/evas_cs2_client.c new file mode 100644 index 0000000000..adc582a8b8 --- /dev/null +++ b/legacy/evas/src/lib/cserve2/evas_cs2_client.c @@ -0,0 +1,742 @@ +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include + +#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 diff --git a/legacy/evas/src/lib/cserve2/evas_cs2_image_data.c b/legacy/evas/src/lib/cserve2/evas_cs2_image_data.c new file mode 100644 index 0000000000..a5e49da396 --- /dev/null +++ b/legacy/evas/src/lib/cserve2/evas_cs2_image_data.c @@ -0,0 +1,23 @@ +#include "config.h" + +#include +#include +#include + +#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 diff --git a/legacy/evas/src/lib/cserve2/evas_cs2_private.h b/legacy/evas/src/lib/cserve2/evas_cs2_private.h new file mode 100644 index 0000000000..5521fd811c --- /dev/null +++ b/legacy/evas/src/lib/cserve2/evas_cs2_private.h @@ -0,0 +1,34 @@ +#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 diff --git a/legacy/evas/src/lib/engines/common/Makefile.am b/legacy/evas/src/lib/engines/common/Makefile.am index 0937394443..262c759ba6 100644 --- a/legacy/evas/src/lib/engines/common/Makefile.am +++ b/legacy/evas/src/lib/engines/common/Makefile.am @@ -6,6 +6,7 @@ MAINTAINERCLEANFILES = Makefile.in 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)\" \ diff --git a/legacy/evas/src/lib/engines/common/evas_image.h b/legacy/evas/src/lib/engines/common/evas_image.h index 300697c487..766c90c680 100644 --- a/legacy/evas/src/lib/engines/common/evas_image.h +++ b/legacy/evas/src/lib/engines/common/evas_image.h @@ -18,6 +18,9 @@ EAPI void evas_common_image_set_alpha_sparse (Image_Entry /* 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); @@ -32,6 +35,8 @@ EAPI void evas_common_image_alpha_line_buffer_free (RGBA_Image * 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); diff --git a/legacy/evas/src/lib/engines/common/evas_image_load.c b/legacy/evas/src/lib/engines/common/evas_image_load.c index 21ac5d40a4..386bb766c5 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_load.c +++ b/legacy/evas/src/lib/engines/common/evas_image_load.c @@ -9,6 +9,9 @@ #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 { @@ -183,6 +186,20 @@ evas_common_load_rgba_image_module_from_file(Image_Entry *ie) } } #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); @@ -333,6 +350,28 @@ evas_common_load_rgba_image_data_from_file(Image_Entry *ie) } #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); diff --git a/legacy/evas/src/lib/engines/common/evas_image_main.c b/legacy/evas/src/lib/engines/common/evas_image_main.c index 0fcb3df864..f8053a8a96 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_main.c +++ b/legacy/evas/src/lib/engines/common/evas_image_main.c @@ -19,6 +19,9 @@ //#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; */ @@ -78,11 +81,38 @@ static const Evas_Cache_Image_Func _evas_common_image_func = 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); @@ -115,6 +145,10 @@ evas_common_image_shutdown(void) // 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 @@ -165,6 +199,12 @@ _evas_common_rgba_image_delete(Image_Entry *ie) #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 @@ -266,6 +306,22 @@ evas_common_rgba_image_unload(Image_Entry *ie) } #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); @@ -333,6 +389,9 @@ _evas_common_rgba_image_surface_alloc(Image_Entry *ie, unsigned int w, unsigned #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; @@ -411,6 +470,11 @@ _evas_common_rgba_image_surface_delete(Image_Entry *ie) 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; @@ -440,6 +504,10 @@ _evas_common_rgba_image_dirty_region(Image_Entry* ie, unsigned int x __UNUSED__, #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); @@ -460,12 +528,20 @@ _evas_common_rgba_image_dirty(Image_Entry *ie_dst, const Image_Entry *ie_src) { #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); @@ -487,7 +563,9 @@ _evas_common_rgba_image_ram_usage(Image_Entry *ie) 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)) @@ -639,6 +717,10 @@ evas_common_image_colorspace_normalize(RGBA_Image *im) { #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) { @@ -702,6 +784,10 @@ evas_common_image_set_cache(unsigned int size) { if (eci) evas_cache_image_set(eci, size); +#ifdef EVAS_CSERVE2 + if (eci2) + evas_cache2_limit_set(eci2, size); +#endif } EAPI int @@ -733,6 +819,14 @@ evas_common_image_cache_get(void) 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) { diff --git a/legacy/evas/src/lib/engines/common/evas_image_private.h b/legacy/evas/src/lib/engines/common/evas_image_private.h index 1bec6c86e9..f40866cfd8 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_private.h +++ b/legacy/evas/src/lib/engines/common/evas_image_private.h @@ -8,8 +8,6 @@ int evas_common_rgba_image_colorspace_set (Image_Entry* dst, 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); diff --git a/legacy/evas/src/lib/engines/common/evas_image_scalecache.c b/legacy/evas/src/lib/engines/common/evas_image_scalecache.c index 0a6b4e63eb..99ecd308c9 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_scalecache.c +++ b/legacy/evas/src/lib/engines/common/evas_image_scalecache.c @@ -8,6 +8,9 @@ #include +#ifdef EVAS_CSERVE2 +#include "evas_cs2_private.h" +#endif #include "evas_common.h" #include "evas_private.h" #include "evas_image_private.h" @@ -523,7 +526,14 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst, 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++; @@ -546,7 +556,14 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst, 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++; @@ -630,7 +647,14 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst, 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) { @@ -733,6 +757,9 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst, #ifdef EVAS_CSERVE || (ie->data1) #endif +#ifdef EVAS_CSERVE2 + || (ie->data1) +#endif ) && (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888))) { @@ -740,7 +767,12 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst, (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); } } } @@ -748,7 +780,14 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst, 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); @@ -771,7 +810,14 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst, #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) { diff --git a/legacy/evas/src/lib/include/evas_common.h b/legacy/evas/src/lib/include/evas_common.h index 89527b93e5..7989ba9bc4 100644 --- a/legacy/evas/src/lib/include/evas_common.h +++ b/legacy/evas/src/lib/include/evas_common.h @@ -435,6 +435,9 @@ typedef void (*Gfx_Func_Copy) (DATA32 *src, DATA32 *dst, int len); 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 /*****************************************************************************/ @@ -569,6 +572,9 @@ struct _Image_Entry EINA_INLIST; Evas_Cache_Image *cache; +#ifdef EVAS_CSERVE2 + Evas_Cache2 *cache2; +#endif const char *cache_key; @@ -614,6 +620,9 @@ struct _Image_Entry 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; diff --git a/legacy/evas/src/modules/engines/buffer/Makefile.am b/legacy/evas/src/modules/engines/buffer/Makefile.am index f8cd36452f..27f491266a 100644 --- a/legacy/evas/src/modules/engines/buffer/Makefile.am +++ b/legacy/evas/src/modules/engines/buffer/Makefile.am @@ -5,6 +5,7 @@ AM_CPPFLAGS = \ -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@ \ diff --git a/legacy/evas/src/modules/engines/buffer/evas_outbuf.c b/legacy/evas/src/modules/engines/buffer/evas_outbuf.c index 0fa1842fe1..7b79ebb263 100644 --- a/legacy/evas/src/modules/engines/buffer/evas_outbuf.c +++ b/legacy/evas/src/modules/engines/buffer/evas_outbuf.c @@ -1,3 +1,11 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef EVAS_CSERVE2 +#include "evas_cs2_private.h" +#endif + #include "evas_common.h" #include "evas_engine.h" @@ -11,6 +19,11 @@ evas_buffer_outbuf_buf_free(Outbuf *buf) { 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); @@ -50,6 +63,14 @@ evas_buffer_outbuf_buf_setup_fb(int w, int h, Outbuf_Depth depth, void *dest, in (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, @@ -58,6 +79,14 @@ evas_buffer_outbuf_buf_setup_fb(int w, int h, Outbuf_Depth depth, void *dest, in 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, @@ -80,6 +109,11 @@ evas_buffer_outbuf_buf_new_region_for_update(Outbuf *buf, int x, int y, int w, i 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) { @@ -87,6 +121,11 @@ evas_buffer_outbuf_buf_new_region_for_update(Outbuf *buf, int x, int y, int w, i ((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); } } @@ -97,7 +136,15 @@ evas_buffer_outbuf_buf_new_region_for_update(Outbuf *buf, int x, int y, int w, i 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 @@ -108,12 +155,26 @@ evas_buffer_outbuf_buf_switch_buffer(Outbuf *buf) 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); + } } } } diff --git a/legacy/evas/src/modules/engines/software_generic/Makefile.am b/legacy/evas/src/modules/engines/software_generic/Makefile.am index fa522f8587..f31810e6de 100644 --- a/legacy/evas/src/modules/engines/software_generic/Makefile.am +++ b/legacy/evas/src/modules/engines/software_generic/Makefile.am @@ -5,6 +5,7 @@ AM_CPPFLAGS = \ -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@ \ diff --git a/legacy/evas/src/modules/engines/software_generic/evas_engine.c b/legacy/evas/src/modules/engines/software_generic/evas_engine.c index cbc709d601..96ed50ca9e 100644 --- a/legacy/evas/src/modules/engines/software_generic/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_generic/evas_engine.c @@ -1,5 +1,8 @@ #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 /* dlopen,dlclose,etc */ @@ -655,24 +658,58 @@ static void * 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); } @@ -691,6 +728,10 @@ eng_image_size_set(void *data __UNUSED__, void *image, int w, int h) { 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); } @@ -699,6 +740,10 @@ eng_image_dirty_region(void *data __UNUSED__, void *image, int x, int y, int w, { 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); } @@ -706,7 +751,7 @@ static void * 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) { @@ -714,6 +759,21 @@ eng_image_data_get(void *data __UNUSED__, void *image, int to_write, DATA32 **im 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) { @@ -756,6 +816,14 @@ eng_image_data_put(void *data, void *image, DATA32 *image_data) 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; } @@ -786,8 +854,15 @@ static void 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); } @@ -795,6 +870,10 @@ static void 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); @@ -810,6 +889,10 @@ eng_image_draw(void *data __UNUSED__, void *context, void *surface, void *image, #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, @@ -822,9 +905,18 @@ eng_image_draw(void *data __UNUSED__, void *context, void *surface, void *image, 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); @@ -916,6 +1008,13 @@ eng_image_map_surface_new(void *data __UNUSED__, int w, int h, int alpha) 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); } diff --git a/legacy/evas/src/modules/engines/software_x11/Makefile.am b/legacy/evas/src/modules/engines/software_x11/Makefile.am index 441a00abe4..1d5d17bca9 100644 --- a/legacy/evas/src/modules/engines/software_x11/Makefile.am +++ b/legacy/evas/src/modules/engines/software_x11/Makefile.am @@ -11,6 +11,7 @@ AM_CPPFLAGS = \ -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@ \ diff --git a/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.c b/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.c index 9662bb31e9..c78814715a 100644 --- a/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.c +++ b/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.c @@ -5,6 +5,9 @@ #include #include +#ifdef EVAS_CSERVE2 +#include "evas_cs2_private.h" +#endif #include "evas_common.h" #include "evas_macros.h" #include "evas_xlib_outbuf.h" @@ -157,7 +160,14 @@ evas_software_xlib_outbuf_free(Outbuf *buf) 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); @@ -411,10 +421,20 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w 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); @@ -432,14 +452,24 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w } 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)) { @@ -451,7 +481,14 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w 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; } @@ -472,7 +509,14 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w 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; } @@ -532,10 +576,18 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w 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); @@ -552,7 +604,12 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w } 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); @@ -561,7 +618,12 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w 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)) { @@ -573,7 +635,14 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w 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; } @@ -594,7 +663,14 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w 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; } @@ -723,7 +799,14 @@ evas_software_xlib_outbuf_flush(Outbuf *buf) 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); @@ -760,11 +843,25 @@ evas_software_xlib_outbuf_flush(Outbuf *buf) 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 } @@ -785,7 +882,14 @@ evas_software_xlib_outbuf_idle_flush(Outbuf *buf) 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 { @@ -800,7 +904,14 @@ evas_software_xlib_outbuf_idle_flush(Outbuf *buf) 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);