evas/cserve2: fix typo that kept cserve2 disabled

now seriously...

Introducing Cache Serve 2.

This cache server will initially load images for clients connected to
it. It starts slave processes to load these images, and share the loaded
images through shm with the clients. All the connection done between
clients and the server goes through sockets.

The cserve2 build option is turned on by default, while the old cserve
was disabled, but in order to make clients use it, the environment
variable EVAS_CSERVE2 must be set, and a server must be running.

Clients will try to find the socket on a specified location using the
environment variable EVAS_CSERVE2_SOCKET. If it's not defined, then the
XDG_RUNTIME_DIR path should be used, and finally HOME, TMPDIR and /tmp.



SVN revision: 70699
This commit is contained in:
Iván Briano 2012-05-03 21:01:31 +00:00
parent b8ade6a7cf
commit 15328efb85
68 changed files with 15033 additions and 50 deletions

View File

@ -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

View File

@ -34,3 +34,4 @@ Nicolas Aguirre <aguirre.nicolas@gmail.com>
Rafal Krypa <r.krypa@samsung.com>
Hyoyoung Chang <hyoyoung@gmail.com>
Jérôme Pinot <ngc891@gmail.com>
Rafael Antognolli <antognolli@profusion.mobi>

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,205 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "evas_cserve2.h"
static Eina_Bool
command_read(int fd, Slave_Command *cmd, void **params)
{
ssize_t ret;
int ints[2], size, got = 0;
char *buf;
ret = read(fd, ints, sizeof(int) * 2);
if (ret < (int)sizeof(int) * 2)
return EINA_FALSE;
size = ints[0];
buf = malloc(size);
if (!buf) return EINA_FALSE;
do {
ret = read(fd, buf + got, size - got);
if (ret < 0)
{
/* EINTR means we were interrupted by a signal before anything
* was sent, and if we are back here it means that signal was
* not meant for us to die. Any other error here is fatal and
* should result in the slave terminating.
*/
if (errno == EINTR)
continue;
free(buf);
return EINA_FALSE;
}
got += ret;
} while (got < size);
*cmd = ints[1];
*params = buf;
return EINA_TRUE;
}
static Eina_Bool
response_send(int fd, Slave_Command cmd, void *resp, int size)
{
int sent = 0, ints[2];
const char *data = resp;
ssize_t ret;
ints[0] = size;
ints[1] = cmd;
ret = write(fd, ints, sizeof(int) * 2);
if (ret < 0)
return EINA_FALSE;
if (!size)
return EINA_TRUE;
do {
ret = write(fd, data + sent, size - sent);
if (ret < 0)
{
/* EINTR means we were interrupted by a signal before anything
* was sent, and if we are back here it means that signal was
* not meant for us to die. Any other error here is fatal and
* should result in the slave terminating.
*/
if (errno == EINTR)
continue;
return EINA_FALSE;
}
sent += ret;
} while (sent < size);
return EINA_TRUE;
}
static Eina_Bool
error_send(int fd, Error_Type err)
{
return response_send(fd, ERROR, &err, sizeof(Error_Type));
}
void *
cserve2_shm_map(const char *name, size_t length, off_t offset)
{
void *map;
int fd;
fd = shm_open(name, O_RDWR, 0);
if (fd == -1)
return MAP_FAILED;
map = mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, offset);
close(fd);
return map;
}
void
cserve2_shm_unmap(void *map, size_t length)
{
munmap(map, length);
}
static Error_Type
image_open(const char *file __UNUSED__, const char *key __UNUSED__, Slave_Msg_Image_Opened *result)
{
memset(result, 0, sizeof(*result));
result->w = 32;
result->h = 32;
result->frame_count = 1;
result->loop_count = 0;
result->loop_hint = 0;
result->alpha = EINA_TRUE;
return CSERVE2_NONE;
}
static Error_Type
image_load(const char *shmfile, Slave_Msg_Image_Load *params)
{
char *map = cserve2_shm_map(shmfile, params->shm.mmap_size,
params->shm.mmap_offset);
if (map == MAP_FAILED)
return CSERVE2_RESOURCE_ALLOCATION_FAILED;
memset(map + params->shm.image_offset, 'A', params->shm.image_size);
return CSERVE2_NONE;
}
int main(int c, char **v)
{
int wfd, rfd;
Slave_Command cmd;
void *params = NULL;;
Eina_Bool quit = EINA_FALSE;
if (c < 3)
return 1;
wfd = atoi(v[1]);
rfd = atoi(v[2]);
while (!quit)
{
if (!command_read(rfd, &cmd, &params))
{
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;
}

View File

@ -0,0 +1,180 @@
#ifndef _EVAS_CSERVE2_H
#define _EVAS_CSERVE2_H
#include <Eina.h>
#include "evas_cs2.h"
#ifdef ERR
#undef ERR
#endif
#define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_bin_log_dom, __VA_ARGS__)
#ifdef DBG
#undef DBG
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_bin_log_dom, __VA_ARGS__)
#ifdef WRN
#undef WRN
#endif
#define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_bin_log_dom, __VA_ARGS__)
#ifdef INF
#undef INF
#endif
#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_bin_log_dom, __VA_ARGS__)
extern int _evas_cserve2_bin_log_dom;
typedef struct _Slave_Proc Slave_Proc;
typedef struct _Shm_Handle Shm_Handle;
typedef enum {
FD_READ = 1,
FD_WRITE = 2,
FD_ERROR = 4
} Fd_Flags;
struct _Client {
unsigned int id;
int socket;
struct {
Eina_Bool reading;
char *buf; // buffer of data being read
int done, size;
Eina_Binbuf *pending; // pending data to send
} msg;
struct {
Eina_Hash *referencing; // indexed by client file id
} files;
struct {
Eina_Hash *referencing; // indexed by client image id
} images;
};
typedef struct _Client Client;
struct _Image_Load_Opts {
unsigned int w, h;
unsigned int rx, ry, rw, rh;
unsigned int scale_down_by;
double dpi;
Eina_Bool orientation;
};
typedef struct _Image_Load_Opts Image_Load_Opts;
typedef enum {
IMAGE_OPEN,
IMAGE_LOAD,
SLAVE_QUIT,
ERROR
} Slave_Command;
struct _Slave_Msg_Image_Open {
Eina_Bool has_opts : 1;
Eina_Bool has_loader_data : 1;
};
struct _Slave_Msg_Image_Opened {
int w, h;
int degree;
int scale; /* used by jpeg when loading in smaller sizes */
int frame_count;
int loop_count;
int loop_hint; /* include Evas.h? Copy the enum around? */
Eina_Bool alpha : 1;
Eina_Bool animated : 1;
Eina_Bool rotated : 1;
Eina_Bool has_loader_data : 1;
};
struct _Slave_Msg_Image_Load {
int w, h;
Image_Load_Opts opts;
struct {
int mmap_offset;
int image_offset;
int mmap_size;
int image_size;
} shm;
Eina_Bool alpha : 1;
Eina_Bool has_loader_data : 1;
};
struct _Slave_Msg_Image_Loaded {
Eina_Bool alpha_sparse : 1;
};
typedef struct _Slave_Msg_Image_Open Slave_Msg_Image_Open;
typedef struct _Slave_Msg_Image_Opened Slave_Msg_Image_Opened;
typedef struct _Slave_Msg_Image_Load Slave_Msg_Image_Load;
typedef struct _Slave_Msg_Image_Loaded Slave_Msg_Image_Loaded;
typedef void (*Fd_Watch_Cb)(int fd, Fd_Flags flags, void *data);
typedef void (*Timeout_Cb)(void); /* void* for compat? */
typedef void (*Main_Loop_Child_Dead_Cb)(int pid, int status); /* void* for compat? */
typedef void (*Slave_Dead_Cb)(Slave_Proc *slave, void *data);
typedef void (*Slave_Read_Cb)(Slave_Proc *slave, Slave_Command cmd, void *msg, void *data);
typedef void (*File_Change_Cb)(const char *path, Eina_Bool deleted, void *data);
void cserve2_client_accept(int fd);
ssize_t cserve2_client_read(Client *client, void *buf, size_t len);
ssize_t cserve2_client_write(Client *client, const void *buf, size_t len);
void cserve2_client_del(Client *client);
void cserve2_client_deliver(Client *client);
void cserve2_client_error_send(Client *client, unsigned int rid, int error_code);
ssize_t cserve2_client_send(Client *client, const void *data, size_t size);
Eina_Bool cserve2_fd_watch_add(int fd, Fd_Flags flags, Fd_Watch_Cb cb, const void *data);
Eina_Bool cserve2_fd_watch_del(int fd);
Eina_Bool cserve2_fd_watch_flags_set(int fd, Fd_Flags flags);
Eina_Bool cserve2_fd_watch_flags_get(int fd, Fd_Flags *flags);
Eina_Bool cserve2_file_change_watch_add(const char *path, File_Change_Cb cb, const void *data);
Eina_Bool cserve2_file_change_watch_del(const char *path);
void cserve2_on_child_dead_set(Main_Loop_Child_Dead_Cb cb);
void cserve2_timeout_cb_set(int t, Timeout_Cb cb);
Eina_Bool cserve2_main_loop_setup(void);
void cserve2_main_loop_run(void);
void cserve2_main_loop_finish(void);
Eina_Bool cserve2_slaves_init(void);
void cserve2_slaves_shutdown(void);
int cserve2_slave_available_get(void);
Eina_Bool cserve2_slave_cmd_dispatch(void *data, Slave_Command cmd, const void *msg, int size);
Slave_Proc *cserve2_slave_run(const char *exe, Slave_Read_Cb read_cb, Slave_Dead_Cb dead_cb, const void *data);
void cserve2_slave_send(Slave_Proc *s, Slave_Command cmd, const char *data, size_t size);
void cserve2_slave_kill(Slave_Proc *s);
void cserve2_message_handler(int fd, Fd_Flags flags, void *data);
Shm_Handle *cserve2_shm_request(size_t size);
void cserve2_shm_unref(Shm_Handle *shm);
const char *cserve2_shm_name_get(const Shm_Handle *shm);
off_t cserve2_shm_map_offset_get(const Shm_Handle *shm);
off_t cserve2_shm_offset_get(const Shm_Handle *shm);
size_t cserve2_shm_map_size_get(const Shm_Handle *shm);
size_t cserve2_shm_size_get(const Shm_Handle *shm);
void cserve2_command_run(Client *client, Message_Type type);
void cserve2_cache_init(void);
void cserve2_cache_shutdown(void);
void cserve2_cache_client_new(Client *client);
void cserve2_cache_client_del(Client *client);
int cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid);
void cserve2_cache_file_close(Client *client, unsigned int client_file_id);
int cserve2_cache_image_opts_set(Client *client, Msg_Setopts *msg);
void cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid);
void cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid);
void cserve2_cache_image_unload(Client *client, unsigned int client_image_id);
void cserve2_cache_requests_process(void);
void cserve2_cache_request_opened(Slave_Msg_Image_Opened *resp, void *data);
void cserve2_cache_request_loaded(Slave_Msg_Image_Loaded *resp, void *data);
void cserve2_cache_request_failed(void *data, Error_Type error);
#endif /* _EVAS_CSERVE2_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,429 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "evas_cserve2.h"
static const char *SOCK_PATH = "/tmp/cserve2.socket";
static unsigned int _rid_count = 0;
static void
debug_msg(const void *buf, int size)
{
const char *str = buf;
int i;
printf("message: ");
for (i = 0; i < size; i++)
printf("%x ", str[i]);
printf("\n");
}
static int
_read_line(char *buf, int size)
{
int len;
char *c;
fgets(buf, size, stdin);
c = strchr(buf, '#');
if (c)
*c = '\0';
else
{
c = strchr(buf, '\n');
if (c)
*c = '\0';
}
len = strlen(buf);
return len + 1;
}
static void *
parse_input_open(int *size)
{
char path[4096];
char key[4096];
char line[4096];
int path_len, key_len;
Msg_Open msg;
char *buf;
int file_id;
_read_line(line, sizeof(line));
path_len = _read_line(path, sizeof(path));
key_len = _read_line(key, sizeof(key));
sscanf(line, "%d", &file_id);
buf = malloc(sizeof(msg) + path_len + key_len);
msg.base.rid = _rid_count++;
msg.base.type = CSERVE2_OPEN;
msg.file_id = file_id;
msg.path_offset = 0;
msg.key_offset = path_len;
memcpy(buf, &msg, sizeof(msg));
memcpy(buf + sizeof(msg), path, path_len);
memcpy(buf + sizeof(msg) + path_len, key, key_len);
*size = sizeof(msg) + path_len + key_len;
return buf;
}
static void *
parse_input_setopts(int *size)
{
Msg_Setopts *msg;
char line[4096];
int file_id, image_id;
double dpi;
int w, h;
int scale;
int rx, ry, rw, rh;
int orientation;
// reading file_id, image_id
_read_line(line, sizeof(line));
sscanf(line, "%d %d", &file_id, &image_id);
// reading load dpi
_read_line(line, sizeof(line));
dpi = atof(line);
// reading load size
_read_line(line, sizeof(line));
sscanf(line, "%d %d", &w, &h);
// reading load scale down
_read_line(line, sizeof(line));
sscanf(line, "%d", &scale);
// reading load region
_read_line(line, sizeof(line));
sscanf(line, "%d %d %d %d", &rx, &ry, &rw, &rh);
// reading orientation
_read_line(line, sizeof(line));
sscanf(line, "%d", &orientation);
msg = calloc(1, sizeof(*msg));
msg->base.rid = _rid_count++;
msg->base.type = CSERVE2_SETOPTS;
msg->file_id = file_id;
msg->image_id = image_id;
msg->opts.dpi = dpi;
msg->opts.w = w;
msg->opts.h = h;
msg->opts.scale_down = scale;
msg->opts.rx = rx;
msg->opts.ry = ry;
msg->opts.rw = rw;
msg->opts.rh = rh;
msg->opts.orientation = !!orientation;
*size = sizeof(*msg);
return msg;
}
static void *
parse_input_load(int *size)
{
Msg_Load *msg;
char line[4096];
int image_id;
// read image_id
_read_line(line, sizeof(line));
sscanf(line, "%d", &image_id);
msg = calloc(1, sizeof(*msg));
msg->base.rid = _rid_count++;
msg->base.type = CSERVE2_LOAD;
msg->image_id = image_id;
*size = sizeof(*msg);
return msg;
}
static void *
parse_input_preload(int *size)
{
Msg_Preload *msg;
char line[4096];
int image_id;
// read image_id
_read_line(line, sizeof(line));
sscanf(line, "%d", &image_id);
msg = calloc(1, sizeof(*msg));
msg->base.rid = _rid_count++;
msg->base.type = CSERVE2_PRELOAD;
msg->image_id = image_id;
*size = sizeof(*msg);
return msg;
}
static void *
parse_input_unload(int *size)
{
Msg_Unload *msg;
char line[4096];
int image_id;
// read image_id
_read_line(line, sizeof(line));
sscanf(line, "%d", &image_id);
msg = calloc(1, sizeof(*msg));
msg->base.rid = _rid_count++;
msg->base.type = CSERVE2_UNLOAD;
msg->image_id = image_id;
*size = sizeof(*msg);
return msg;
}
static void *
parse_input_close(int *size)
{
Msg_Close *msg;
char line[4096];
int file_id;
// read file_id
_read_line(line, sizeof(line));
sscanf(line, "%d", &file_id);
msg = calloc(1, sizeof(*msg));
msg->base.rid = _rid_count++;
msg->base.type = CSERVE2_CLOSE;
msg->file_id = file_id;
*size = sizeof(*msg);
return msg;
}
static void
parse_answer_opened(const void *buf)
{
const Msg_Opened *msg = buf;
printf("OPENED rid = %d\n", msg->base.rid);
printf("size: %dx%d, alpha: %d\n\n",
msg->image.w, msg->image.h, msg->image.alpha);
}
static void
parse_answer_setoptsed(const void *buf)
{
const Msg_Setoptsed *msg = buf;
printf("SETOPTSED rid = %d\n", msg->base.rid);
}
static void
parse_answer_loaded(const void *buf)
{
const Msg_Loaded *msg = buf;
const char *path;
path = ((const char *)msg) + sizeof(*msg);
printf("LOADED rid = %d\n", msg->base.rid);
printf("shm mmap_offset = 0x%x, use_offset = 0x%x, mmap size = %d bytes\n",
msg->shm.mmap_offset, msg->shm.use_offset, msg->shm.mmap_size);
printf("shm path: \"%s\"\n\n", path);
}
static void
parse_answer_preloaded(const void *buf)
{
const Msg_Preloaded *msg = buf;
printf("PRELOADED rid = %d\n", msg->base.rid);
}
static void
parse_answer_error(const void *buf)
{
const Msg_Error *msg = buf;
printf("ERROR rid = %d, error = %d\n", msg->base.rid, msg->error);
}
static void
parse_answer(const void *buf)
{
const Msg_Base *msg = buf;
switch (msg->type)
{
case CSERVE2_OPENED:
parse_answer_opened(buf);
break;
case CSERVE2_SETOPTSED:
parse_answer_setoptsed(buf);
break;
case CSERVE2_LOADED:
parse_answer_loaded(buf);
break;
case CSERVE2_PRELOADED:
parse_answer_preloaded(buf);
break;
case CSERVE2_ERROR:
parse_answer_error(buf);
break;
default:
printf("unhandled answer: %d\n", msg->type);
}
}
static struct {
const char *name;
Message_Type type;
void *(*parse_func)(int *size);
} _msg_types[] = {
{ "OPEN", CSERVE2_OPEN, parse_input_open },
{ "OPENED", CSERVE2_OPENED, NULL },
{ "SETOPTS", CSERVE2_SETOPTS, parse_input_setopts },
{ "SETOPTSED", CSERVE2_SETOPTSED, NULL },
{ "LOAD", CSERVE2_LOAD, parse_input_load },
{ "LOADED", CSERVE2_LOADED, NULL },
{ "PRELOAD", CSERVE2_PRELOAD, parse_input_preload },
{ "PRELOADED", CSERVE2_PRELOADED, NULL },
{ "UNLOAD", CSERVE2_UNLOAD, parse_input_unload },
{ "CLOSE", CSERVE2_CLOSE, parse_input_close },
{ NULL, 0, NULL }
};
int main(void)
{
int s, t, len, skip_cmd = 0;
struct sockaddr_un remote;
char msgbuf[4096];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
printf("Trying to connect...\n");
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *)&remote, len) == -1)
{
perror("connect");
exit(1);
}
printf("Connected.\n");
while(!feof(stdin))
{
char cmd[1024];
int i;
int size;
void *msg;
if (skip_cmd)
skip_cmd = 0;
else
printf("\n> ");
fgets(cmd, sizeof(cmd), stdin);
len = strlen(cmd) - 1;
cmd[len] = '\0';
if (!len)
{
skip_cmd = 1;
continue;
}
for (i = 0; _msg_types[i].name; i++)
{
if (!strcmp(cmd, _msg_types[i].name))
break;
}
// discards the end of the message if we can't parse it
if (!_msg_types[i].name)
{
printf("Invalid command.\n");
continue;
}
if (!_msg_types[i].parse_func)
{
printf("Command %s still unhandled.\n", _msg_types[i].name);
continue;
}
msg = _msg_types[i].parse_func(&size);
if (send(s, &size, sizeof(size), MSG_NOSIGNAL) == -1)
{
perror("send size");
exit(1);
}
if (send(s, msg, size, MSG_NOSIGNAL) == -1)
{
perror("send");
exit(1);
}
free(msg);
usleep(100000);
if ((t=recv(s, &size, sizeof(size), MSG_DONTWAIT)) > 0)
{
int len = recv(s, msgbuf, size, 0);
printf("size of received message: %d\n", len);
if (len != size)
{
printf("couldn't read entire message.\n");
continue;
}
debug_msg(&size, sizeof(size));
debug_msg(msgbuf, size);
parse_answer(msgbuf);
}
else
{
if (t < 0 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
continue;
else fprintf(stderr, "Server closed connection\n");
exit(1);
}
}
close(s);
return 0;
}

View File

@ -0,0 +1,456 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "evas_cserve2.h"
#ifdef CSERVE2_BIN_DEFAULT_COLOR
#undef CSERVE2_BIN_DEFAULT_COLOR
#endif
#define CSERVE2_BIN_DEFAULT_COLOR EINA_COLOR_BLUE
#define MAX_SLAVES 3
struct _Slave_Worker {
EINA_INLIST;
void *data;
Slave_Proc *slave;
Eina_Binbuf *ret;
int ret_size;
Eina_Bool done;
Eina_Bool delete_me;
};
typedef struct _Slave_Worker Slave_Worker;
int _evas_cserve2_bin_log_dom = -1;
static unsigned int _client_id = 0;
static Eina_Hash *client_list = NULL;
static Eina_Inlist *slaves_idle = NULL;
static Eina_Inlist *slaves_working = NULL;
void
cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
{
int size;
Msg_Error msg;
// clear the struct with possible paddings, since it is not aligned.
memset(&msg, 0, sizeof(msg));
msg.base.rid = rid;
msg.base.type = CSERVE2_ERROR;
msg.error = error_code;
size = sizeof(msg);
cserve2_client_send(client, &size, sizeof(size));
cserve2_client_send(client, &msg, sizeof(msg));
}
static void
_cserve2_client_image_setoptsed(Client *client, unsigned int rid)
{
int size;
Msg_Setoptsed msg;
memset(&msg, 0, sizeof(msg));
msg.base.rid = rid;
msg.base.type = CSERVE2_SETOPTSED;
size = sizeof(msg);
cserve2_client_send(client, &size, sizeof(size));
cserve2_client_send(client, &msg, size);
}
static void
_slave_dead_cb(Slave_Proc *s __UNUSED__, void *data)
{
Slave_Worker *sw = data;
if (sw->delete_me)
{
DBG("Slave killed by cserve2. Restart routine.");
free(sw);
return;
}
if (!sw->data)
{
WRN("Slave died with no pending job, but not requested.");
slaves_idle = eina_inlist_remove(slaves_idle, EINA_INLIST_GET(sw));
free(sw);
return;
}
slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));
if (!sw->done)
cserve2_cache_request_failed(sw->data, CSERVE2_LOADER_DIED);
if (sw->ret)
eina_binbuf_free(sw->ret);
free(sw);
}
static void
_slave_read_error(Slave_Worker *sw, void *msg)
{
Error_Type *error = msg;
cserve2_cache_request_failed(sw->data, *error);
}
static void
_slave_read_cb(Slave_Proc *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
{
Slave_Worker *sw = data;
DBG("Received reply command '%d' from slave '%p'", cmd, sw->slave);
switch (cmd)
{
case IMAGE_OPEN:
cserve2_cache_request_opened(msg, sw->data);
sw->done = EINA_TRUE;
break;
case IMAGE_LOAD:
cserve2_cache_request_loaded(msg, sw->data);
sw->done = EINA_TRUE;
break;
case ERROR:
_slave_read_error(sw, msg);
break;
default:
ERR("Unrecognized command received from slave: %d", cmd);
}
free(msg);
// slave finishes its work, put it back to idle list
sw->data = NULL;
slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));
if (!sw->delete_me) // if it is being deleted, it shouldn't be in any list
slaves_idle = eina_inlist_append(slaves_idle, EINA_INLIST_GET(sw));
cserve2_cache_requests_process();
}
int
cserve2_slave_available_get(void)
{
return MAX_SLAVES - eina_inlist_count(slaves_working);
}
Eina_Bool
cserve2_slave_cmd_dispatch(void *data, Slave_Command cmd, const void *msg, int size)
{
Slave_Worker *sw;
char *exe;
DBG("Dispatching command to slave. %d idle slaves, %d working slaves.",
eina_inlist_count(slaves_idle), eina_inlist_count(slaves_working));
// first check if there's an available slave
if (slaves_idle)
{
sw = EINA_INLIST_CONTAINER_GET(slaves_idle, Slave_Worker);
slaves_idle = eina_inlist_remove(slaves_idle, slaves_idle);
slaves_working = eina_inlist_append(slaves_working,
EINA_INLIST_GET(sw));
sw->data = data;
DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
cserve2_slave_send(sw->slave, cmd, msg, size);
return EINA_TRUE;
}
// no available slave, start a new one
sw = calloc(1, sizeof(Slave_Worker));
if (!sw) return EINA_FALSE;
sw->data = data;
exe = getenv("EVAS_CSERVE2_SLAVE");
if (!exe) exe = "evas_cserve2_slave";
sw->slave = cserve2_slave_run(exe, _slave_read_cb, _slave_dead_cb, sw);
if (!sw->slave)
{
ERR("Could not launch slave process");
cserve2_cache_request_failed(data, CSERVE2_LOADER_EXEC_ERR);
free(sw);
return EINA_FALSE;
}
DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
cserve2_slave_send(sw->slave, cmd, msg, size);
slaves_working = eina_inlist_append(slaves_working, EINA_INLIST_GET(sw));
return EINA_TRUE;
}
static void
_cserve2_client_close(Client *client)
{
Msg_Close *msg = (Msg_Close *)client->msg.buf;
INF("Received CLOSE command: RID=%d", msg->base.rid);
INF("File_ID: %d\n", msg->file_id);
cserve2_cache_file_close(client, msg->file_id);
}
static void
_cserve2_client_unload(Client *client)
{
Msg_Unload *msg = (Msg_Unload *)client->msg.buf;
INF("Received UNLOAD command: RID=%d", msg->base.rid);
INF("Image_ID: %d\n", msg->image_id);
cserve2_cache_image_unload(client, msg->image_id);
}
static void
_cserve2_client_preload(Client *client)
{
Msg_Preload *msg = (Msg_Preload *)client->msg.buf;
INF("Received PRELOAD command: RID=%d", msg->base.rid);
INF("Image_ID: %d\n", msg->image_id);
cserve2_cache_image_preload(client, msg->image_id, msg->base.rid);
cserve2_cache_requests_process();
}
static void
_cserve2_client_load(Client *client)
{
Msg_Load *msg = (Msg_Load *)client->msg.buf;
INF("Received LOAD command: RID=%d", msg->base.rid);
INF("Image_ID: %d\n", msg->image_id);
cserve2_cache_image_load(client, msg->image_id, msg->base.rid);
cserve2_cache_requests_process();
}
static void
_cserve2_client_setopts(Client *client)
{
Msg_Setopts *msg = (Msg_Setopts *)client->msg.buf;
INF("Received SETOPTS command: RID=%d", msg->base.rid);
INF("File_ID: %d, Image_ID: %d", msg->file_id, msg->image_id);
INF("Load Options:");
INF("\tdpi: %03.1f", msg->opts.dpi);
INF("\tsize: %dx%d", msg->opts.w, msg->opts.h);
INF("\tscale down: %d", msg->opts.scale_down);
INF("\tregion: %d,%d + %dx%d",
msg->opts.rx, msg->opts.ry, msg->opts.rw, msg->opts.rh);
INF("\torientation: %d\n", msg->opts.orientation);
if (cserve2_cache_image_opts_set(client, msg) != 0)
return;
_cserve2_client_image_setoptsed(client, msg->base.rid);
}
static void
_cserve2_client_open(Client *client)
{
Msg_Open *msg = (Msg_Open *)client->msg.buf;
const char *path, *key;
path = ((const char *)msg) + sizeof(*msg) + msg->path_offset;
key = ((const char *)msg) + sizeof(*msg) + msg->key_offset;
INF("Received OPEN command: RID=%d", msg->base.rid);
INF("File_ID: %d, path=\"%s\", key=\"%s\"\n",
msg->file_id, path, key);
cserve2_cache_file_open(client, msg->file_id, path, key, msg->base.rid);
cserve2_cache_requests_process();
}
void
cserve2_command_run(Client *client, Message_Type type)
{
switch (type)
{
case CSERVE2_OPEN:
_cserve2_client_open(client);
break;
case CSERVE2_SETOPTS:
_cserve2_client_setopts(client);
break;
case CSERVE2_LOAD:
_cserve2_client_load(client);
break;
case CSERVE2_PRELOAD:
_cserve2_client_preload(client);
break;
case CSERVE2_UNLOAD:
_cserve2_client_unload(client);
break;
case CSERVE2_CLOSE:
_cserve2_client_close(client);
break;
default:
WRN("Unhandled message");
}
}
static void
_slave_quit_send(Slave_Worker *sw)
{
cserve2_slave_send(sw->slave, SLAVE_QUIT, NULL, 0);
}
static void
_slaves_restart(void)
{
Slave_Worker *list, *sw;
while (slaves_idle) // remove idle workers from idle list
{
sw = EINA_INLIST_CONTAINER_GET(slaves_idle, Slave_Worker);
slaves_idle = eina_inlist_remove(slaves_idle, slaves_idle);
sw->delete_me = EINA_TRUE;
_slave_quit_send(sw);
}
// working workers will be removed from the working list when they
// finish processing their jobs
list = EINA_INLIST_CONTAINER_GET(slaves_working, Slave_Worker);
EINA_INLIST_FOREACH(list, sw)
{
sw->delete_me = EINA_TRUE;
_slave_quit_send(sw);
}
}
static void
_timeout_cb(void)
{
static unsigned int slaves_restart = 0;
slaves_restart++;
if (slaves_restart == 10)
{
DBG("kill slaves");
_slaves_restart();
slaves_restart = 0;
}
cserve2_timeout_cb_set(3000, _timeout_cb);
}
void
cserve2_client_accept(int fd)
{
Client *client = calloc(1, sizeof(*client));
client->socket = fd;
client->id = _client_id++;
while (eina_hash_find(client_list, &client->id))
client->id = _client_id++;
if (!eina_hash_add(client_list, &client->id, client))
{
Eina_Error err = eina_error_get();
ERR("Could not add client to the list: \"%s\"",
eina_error_msg_get(err));
free(client);
close(fd);
}
cserve2_fd_watch_add(fd, FD_READ | FD_ERROR, cserve2_message_handler,
client);
INF("Client %d connection accepted.", client->id);
cserve2_cache_client_new(client);
}
void
cserve2_client_del(Client *client)
{
eina_hash_del_by_key(client_list, &client->id);
}
static void
_client_free(void *data)
{
Client *client = data;
cserve2_cache_client_del(client);
if (client->msg.pending)
eina_binbuf_free(client->msg.pending);
cserve2_fd_watch_del(client->socket);
close(client->socket);
free(data);
}
static void
_clients_setup(void)
{
client_list = eina_hash_int32_new(_client_free);
}
static void
_clients_finish(void)
{
eina_hash_free(client_list);
}
int
main(int argc __UNUSED__, const char *argv[] __UNUSED__)
{
eina_init();
_evas_cserve2_bin_log_dom = eina_log_domain_register
("evas_cserve2_bin", CSERVE2_BIN_DEFAULT_COLOR);
if (_evas_cserve2_bin_log_dom < 0)
{
EINA_LOG_ERR("impossible to create a log domain.");
eina_shutdown();
exit(1);
}
if (!cserve2_main_loop_setup())
{
ERR("could not setup main loop.");
goto error;
}
if (!cserve2_slaves_init())
{
ERR("Could not init slaves subsystem.");
goto error;
}
cserve2_cache_init();
_clients_setup();
cserve2_timeout_cb_set(3000, _timeout_cb);
cserve2_main_loop_run();
_clients_finish();
cserve2_cache_shutdown();
_slaves_restart();
cserve2_slaves_shutdown();
cserve2_main_loop_finish();
eina_log_domain_unregister(_evas_cserve2_bin_log_dom);
eina_shutdown();
return 0;
error:
eina_log_domain_unregister(_evas_cserve2_bin_log_dom);
eina_shutdown();
exit(1);
}

View File

@ -0,0 +1,779 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "evas_cserve2.h"
#include <errno.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#define MAX_EPOLL_EVENTS 10
#define MAX_INCOMING_CONN 10
struct _Watch_Data
{
int fd;
Fd_Flags flags;
Fd_Watch_Cb callback;
const void *user_data;
};
typedef struct _Watch_Data Watch_Data;
struct _Inotify_Data
{
EINA_INLIST;
const char *path;
int watchid;
File_Change_Cb cb;
const void *data;
};
typedef struct _Inotify_Data Inotify_Data;
static int epoll_fd = -1;
static int signal_fd = -1;
static int socket_fd = -1;
static int inotify_fd = -1;
static struct sockaddr_un socket_local;
static Eina_Hash *watch_list;
static Eina_Hash *inotify_path_hash;
static Eina_Hash *inotify_id_hash;
static Eina_Bool running;
static Eina_Bool terminate;
static int timeout = -1; // in miliseconds
static long timeout_time = 0; // in miliseconds
static Timeout_Cb timeout_func = NULL;
static Main_Loop_Child_Dead_Cb reap_children_func = NULL;
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX sizeof(socket_local.sun_path)
#endif
static void
_signal_handle_child(struct signalfd_siginfo *sinfo __UNUSED__)
{
int status;
pid_t pid;
while ((pid = waitpid(0, &status, WNOHANG)) > 0)
{
if (reap_children_func)
{
reap_children_func(pid, status);
continue;
}
DBG("Received SIGCHLD and no handler is set.");
if (WIFEXITED(status))
DBG("Child '%d' exited with status '%d'.", pid,
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
DBG("Child '%d' exited with signal '%d'.", pid,
WTERMSIG(status));
}
}
static void
_signal_handle_int(struct signalfd_siginfo *sinfo __UNUSED__)
{
DBG("Received SIGINT. Honoring request.");
terminate = EINA_TRUE;
}
static void
_signal_handle_term(struct signalfd_siginfo *sinfo __UNUSED__)
{
DBG("Received SIGTERM. Honoring request.");
terminate = EINA_TRUE;
}
static void
_signalfd_handler(int fd, Fd_Flags flags __UNUSED__, void *data __UNUSED__)
{
struct signalfd_siginfo sinfo;
ssize_t ret;
for (;;)
{
ret = read(fd, &sinfo, sizeof(struct signalfd_siginfo));
if (ret == -1)
{
if (errno == EAGAIN)
break;
ERR("Error reading from signal fd: %m.");
return;
}
switch(sinfo.ssi_signo)
{
case SIGCHLD:
_signal_handle_child(&sinfo);
break;
case SIGINT:
_signal_handle_int(&sinfo);
break;
case SIGTERM:
_signal_handle_term(&sinfo);
break;
default:
ERR("Caught unexpected signal '%d'.", sinfo.ssi_signo);
}
}
}
static int
_signalfd_setup(void)
{
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
{
ERR("Could not set mask of handled signals.");
return -1;
}
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_fd == -1)
ERR("Could not create file descriptor from signalfd.");
/* ignore SIGPIPE so it's handled by write() and send() as needed */
signal(SIGPIPE, SIG_IGN);
return signal_fd;
}
static void
_signalfd_finish(void)
{
sigset_t mask;
cserve2_fd_watch_del(signal_fd);
sigemptyset(&mask);
sigprocmask(SIG_BLOCK, NULL, &mask);
close(signal_fd);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
signal(SIGPIPE, SIG_DFL);
}
static void
_socketfd_handler(int fd __UNUSED__, Fd_Flags flags __UNUSED__, void *data __UNUSED__)
{
struct sockaddr_un remote;
unsigned int len;
int s;
len = sizeof(struct sockaddr_un);
s = accept4(socket_fd, &remote, &len, SOCK_CLOEXEC);
if (s == -1)
{
ERR("Could not accept socket: \"%s\"", strerror(errno));
return;
}
cserve2_client_accept(s);
}
static void
_socket_path_set(char *path)
{
char *env;
char buf[UNIX_PATH_MAX];
env = getenv("EVAS_CSERVE2_SOCKET");
if (env && env[0])
{
strncpy(path, env, UNIX_PATH_MAX - 1);
return;
}
env = getenv("XDG_RUNTIME_DIR");
if (!env || !env[0])
{
env = getenv("HOME");
if (!env || !env[0])
{
env = getenv("TMPDIR");
if (!env || !env[0])
env = "/tmp";
}
}
snprintf(buf, sizeof(buf), "%s/evas-cserve2-%x.socket", env, getuid());
/* FIXME: check we can actually create this socket */
strcpy(path, buf);
}
static int
_socketfd_setup(void)
{
int s;
int len;
s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (s == -1)
{
ERR("Could not create socketfd: \"%s\"", strerror(errno));
return -1;
}
socket_local.sun_family = AF_UNIX;
_socket_path_set(socket_local.sun_path);
DBG("Using '%s' as server socket.", socket_local.sun_path);
unlink(socket_local.sun_path);
len = strlen(socket_local.sun_path) + sizeof(socket_local.sun_family);
if (bind(s, (struct sockaddr *)&socket_local, len) == -1)
{
ERR("Could not bind socketfd: \"%s\"", strerror(errno));
close(s);
return -1;
}
if (listen(s, MAX_INCOMING_CONN) == -1)
{
ERR("Could not listen on socketfd: \"%s\"", strerror(errno));
close(s);
unlink(socket_local.sun_path);
return -1;
}
socket_fd = s;
return s;
}
static void
_socketfd_finish(void)
{
close(socket_fd);
unlink(socket_local.sun_path);
}
static void
_inotifyfd_handler(int fd, Fd_Flags flags, void *data __UNUSED__)
{
char buffer[16384];
int i = 0;
ssize_t size;
if (flags & FD_ERROR)
{
ERR("Error on inotify file handler, what to do?");
return;
}
size = read(fd, buffer, sizeof(buffer));
while (i < size)
{
struct inotify_event *event;
int event_size;
Eina_Inlist *ids, *itr;
Inotify_Data *id;
Eina_Bool deleted;
event = (struct inotify_event *)&buffer[i];
event_size = sizeof(struct inotify_event) + event->len;
i += event_size;
ids = eina_hash_find(inotify_id_hash, &event->wd);
if (!ids) continue;
deleted = !!(event->mask
& (IN_DELETE_SELF | IN_MOVE_SELF
| IN_IGNORED | IN_UNMOUNT));
EINA_INLIST_FOREACH_SAFE(ids, itr, id)
id->cb(id->path, deleted, (void *)id->data);
}
}
static void
_inotify_id_hash_free_cb(void *data)
{
Eina_Inlist *list = data;
while (list)
{
Inotify_Data *id;
id = EINA_INLIST_CONTAINER_GET(list, Inotify_Data);
list = eina_inlist_remove(list, list);
eina_stringshare_del(id->path);
free(id);
}
}
static int
_inotifyfd_setup(void)
{
inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (inotify_fd == -1)
{
ERR("Could not create inotifyfd: \"%s\"", strerror(errno));
return -1;
}
inotify_path_hash = eina_hash_string_superfast_new(NULL);
inotify_id_hash = eina_hash_int32_new(_inotify_id_hash_free_cb);
return inotify_fd;
}
static void
_inotifyfd_finish(void)
{
close(inotify_fd);
eina_hash_free(inotify_path_hash);
eina_hash_free(inotify_id_hash);
}
static void
_watch_data_free_cb(void *data)
{
free(data);
}
Eina_Bool
cserve2_main_loop_setup(void)
{
int sfd;
int socket;
int ifd;
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd < 0)
{
ERR("Could not create epoll fd.");
return EINA_FALSE;
}
watch_list = eina_hash_int32_new(_watch_data_free_cb);
if (!watch_list)
{
ERR("Could not create watch list hash struct.");
close(epoll_fd);
return EINA_FALSE;
}
sfd = _signalfd_setup();
if (sfd == -1)
{
ERR("Could not setup signalfd.");
close(epoll_fd);
eina_hash_free(watch_list);
return EINA_FALSE;
}
DBG("Add watch for signal fd: %d", sfd);
if (!cserve2_fd_watch_add(sfd, FD_READ, _signalfd_handler, NULL))
{
ERR("Could not add watch for signalfd.");
close(sfd);
close(epoll_fd);
eina_hash_free(watch_list);
return EINA_FALSE;
}
socket = _socketfd_setup();
if (socket == -1)
{
ERR("Could not setup socketfd.");
goto error_socket;
}
DBG("Add watch for socket fd: %d", socket);
if (!cserve2_fd_watch_add(socket, FD_READ, _socketfd_handler, NULL))
{
ERR("Could not add watch for socketf.");
close(socket);
goto error_socket;
}
ifd = _inotifyfd_setup();
if (ifd == -1)
{
ERR("Could not setup inotify.");
goto error_inotify;
}
DBG("Add watch for inotify fd: %d", ifd);
if (!cserve2_fd_watch_add(ifd, FD_READ, _inotifyfd_handler, NULL))
{
ERR("Could not add watch for inotifyfd.");
close(ifd);
goto error_inotify;
}
return EINA_TRUE;
error_inotify:
_socketfd_finish();
error_socket:
close(sfd);
close(epoll_fd);
eina_hash_free(watch_list);
return EINA_FALSE;
}
void
cserve2_main_loop_finish(void)
{
_socketfd_finish();
_signalfd_finish();
_inotifyfd_finish();
eina_hash_free(watch_list);
close(epoll_fd);
}
Eina_Bool
cserve2_fd_watch_add(int fd, Fd_Flags flags, Fd_Watch_Cb cb, const void *data)
{
Watch_Data *w_data;
struct epoll_event ev;
int err;
DBG("Add watch for fd %d, flags = 0x%x", fd, flags);
if ((fd < 0) || (!cb))
{
ERR("Can't add watch: fd = %d, callback = %p", fd, cb);
return EINA_FALSE;
}
w_data = calloc(1, sizeof(*w_data));
w_data->fd = fd;
w_data->flags = flags;
w_data->callback = cb;
w_data->user_data = data;
if (!eina_hash_add(watch_list, &fd, w_data))
{
ERR("Could not add watch for fd %d to the hash.", fd);
free(w_data);
return EINA_FALSE;
}
memset(&ev, 0, sizeof(ev));
if (flags & FD_READ)
ev.events |= EPOLLIN;
if (flags & FD_WRITE)
ev.events |= EPOLLOUT;
ev.data.ptr = w_data;
err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
if (!err < 0)
{
ERR("Could not create epoll watch for fd %d.", fd);
eina_hash_del(watch_list, &fd, NULL);
return EINA_FALSE;
}
return EINA_TRUE;
}
Eina_Bool
cserve2_fd_watch_flags_set(int fd, Fd_Flags flags)
{
Watch_Data *w_data;
struct epoll_event ev;
int err;
DBG("Set watch flags for fd %d, flags = 0x%x", fd, flags);
if (fd < 0)
{
ERR("Can't modify watch: fd = %d", fd);
return EINA_FALSE;
}
w_data = eina_hash_find(watch_list, &fd);
if (!w_data)
{
ERR("Couldn't find data for fd %d: not being watched.", fd);
return EINA_FALSE;
}
if (flags == w_data->flags)
return EINA_TRUE;
memset(&ev, 0, sizeof(ev));
if (flags & FD_READ)
ev.events |= EPOLLIN;
if (flags & FD_WRITE)
ev.events |= EPOLLOUT;
ev.data.ptr = w_data;
err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev);
if (err < 0)
{
ERR("Could not modify epoll watch for fd: %d", fd);
return EINA_FALSE;
}
return EINA_TRUE;
}
Eina_Bool
cserve2_fd_watch_flags_get(int fd, Fd_Flags *flags)
{
Watch_Data *w_data;
if (fd < 0)
{
ERR("Can't get flags for watch: fd = %d", fd);
return EINA_FALSE;
}
w_data = eina_hash_find(watch_list, &fd);
if (!w_data)
{
ERR("Couldn't find data for fd: %d. Is it really being watched?", fd);
return EINA_FALSE;
}
*flags = w_data->flags;
return EINA_TRUE;
}
Eina_Bool
cserve2_fd_watch_del(int fd)
{
int err;
DBG("Remove watch for fd %d", fd);
if (fd < 0)
return EINA_FALSE;
if (!eina_hash_del(watch_list, &fd, NULL))
ERR("Could not remove watch for fd %d from watch list hash.", fd);
err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
if (err < 0)
{
ERR("Could not remove epoll watch for fd %d.", fd);
return EINA_FALSE;
}
return EINA_TRUE;
}
Eina_Bool
cserve2_file_change_watch_add(const char *path, File_Change_Cb cb, const void *data)
{
Inotify_Data *id;
Eina_Inlist *ids;
unsigned int mask = IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF;
id = eina_hash_find(inotify_path_hash, path);
if (id)
{
ERR("Attempt to watch changes for path '%s', which is already "
"being watched.", path);
return EINA_FALSE;
}
id = calloc(1, sizeof(Inotify_Data));
if (!id)
{
ERR("Could not alloc Inotify_Data instance.");
return EINA_FALSE;
}
id->watchid = inotify_add_watch(inotify_fd, path, mask);
if (id->watchid == -1)
{
ERR("Could not add inotify watch for %s: %m.", path);
free(id);
return EINA_FALSE;
}
id->path = eina_stringshare_add(path);
id->cb = cb;
id->data = data;
eina_hash_direct_add(inotify_path_hash, id->path, id);
ids = eina_hash_find(inotify_id_hash, &id->watchid);
ids = eina_inlist_append(ids, EINA_INLIST_GET(id));
eina_hash_set(inotify_id_hash, &id->watchid, ids);
return EINA_TRUE;
}
Eina_Bool
cserve2_file_change_watch_del(const char *path)
{
Inotify_Data *id;
Eina_Inlist *ids;
int wd;
id = eina_hash_set(inotify_path_hash, path, NULL);
if (!id)
{
ERR("Requested to remove change watch for %s, but it's not being "
"watched.", path);
return EINA_FALSE;
}
ids = eina_hash_find(inotify_id_hash, &id->watchid);
ids = eina_inlist_remove(ids, EINA_INLIST_GET(id));
eina_hash_set(inotify_id_hash, &id->watchid, ids);
wd = id->watchid;
eina_stringshare_del(id->path);
free(id);
if (!ids)
{
if (inotify_rm_watch(inotify_fd, wd) == -1)
{
ERR("Could not remove change watch for %s: %m", path);
return EINA_FALSE;
}
}
return EINA_TRUE;
}
static void
_update_timeout(void)
{
struct timeval timev;
long cur_time;
if (timeout <= 0)
return;
gettimeofday(&timev, NULL);
cur_time = timev.tv_sec * 1000 + timev.tv_usec / 1000;
timeout -= cur_time - timeout_time;
timeout_time = cur_time;
if (timeout < 0)
timeout = 0;
}
void
cserve2_timeout_cb_set(int t, Timeout_Cb cb)
{
struct timeval timev;
if (cb && t <= 0)
{
ERR("timeout must be a value greater than 0 to set a callback."
" given timeout: %d miliseconds", t);
return;
}
if (!cb)
{
DBG("Removing timeout callback.");
timeout = -1;
cb = NULL;
return;
}
//DBG("Setting timeout to: %d miliseconds", t);
gettimeofday(&timev, NULL);
timeout_time = timev.tv_sec * 1000 + timev.tv_usec / 1000;
timeout = t;
timeout_func = cb;
}
void
cserve2_on_child_dead_set(Main_Loop_Child_Dead_Cb cb)
{
reap_children_func = cb;
}
void
cserve2_main_loop_run(void)
{
running = EINA_TRUE;
terminate = EINA_FALSE;
for (;;)
{
struct epoll_event events[MAX_EPOLL_EVENTS];
int n, nfds;
if (terminate)
break;
nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, timeout);
if (nfds < 0)
{
ERR("An error occurred when reading the epoll fd.");
ERR("%s", strerror(errno));
break;
}
if (nfds == 0) // timeout occurred
{
timeout = -1;
if (!timeout_func)
ERR("Timeout expired, but no timeout function set.");
else
timeout_func();
}
for (n = 0; n < nfds; n++)
{
Watch_Data *data = events[n].data.ptr;
Fd_Flags flags = 0;
if (!data)
continue;
if (!data->callback)
continue;
if (events[n].events & EPOLLIN)
flags |= FD_READ;
if (events[n].events & EPOLLOUT)
flags |= FD_WRITE;
if (events[n].events & EPOLLERR)
flags |= FD_ERROR;
data->callback(data->fd, flags, (void *)data->user_data);
}
_update_timeout();
}
running = EINA_FALSE;
}
ssize_t
cserve2_client_read(Client *client, void *buf, size_t len)
{
return recv(client->socket, buf, len, MSG_DONTWAIT);
}
ssize_t
cserve2_client_write(Client *client, const void *data, size_t size)
{
return send(client->socket, data, size, MSG_NOSIGNAL | MSG_DONTWAIT);
}

View File

@ -0,0 +1,189 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <string.h>
#include "evas_cserve2.h"
// #define DEBUG_MSG 1
static void
debug_msg(const char *typestr, const void *buf, int size)
{
#ifdef DEBUG_MSG
const char *str = buf;
int i;
printf("message %s: ", typestr);
for (i = 0; i < size; i++)
printf("%x ", str[i]);
printf("\n");
#endif
}
static void
_client_msg_allocate_buf(Client *client, int msgsize)
{
client->msg.reading = EINA_TRUE;
client->msg.buf = malloc(msgsize + 1);
client->msg.size = msgsize;
client->msg.done = 0;
}
static void
_client_msg_free(Client *client)
{
client->msg.reading = EINA_FALSE;
free(client->msg.buf);
}
static void
_client_msg_parse(Client *client)
{
Msg_Base *msg = (Msg_Base *)client->msg.buf;
DBG("Message received. Size: %d; type = %d",
client->msg.size, msg->type);
cserve2_command_run(client, msg->type);
}
static void
_client_msg_read(Client *client, int done)
{
client->msg.done += done;
if (client->msg.done == client->msg.size)
{
debug_msg("received", client->msg.buf, client->msg.size);
_client_msg_parse(client);
_client_msg_free(client);
}
}
void
cserve2_message_handler(int fd __UNUSED__, Fd_Flags flags, void *data)
{
Client *client = data;
int len;
int msgsize;
if (flags & FD_ERROR)
{
ERR("Error on socket for client: %d", client->id);
goto client_close;
}
if (flags & FD_WRITE)
cserve2_client_deliver(client);
if (!(flags & FD_READ))
return;
if (!client->msg.reading)
len = cserve2_client_read(client, &msgsize, sizeof(msgsize));
else
len = cserve2_client_read(client, &client->msg.buf[client->msg.done],
client->msg.size - client->msg.done);
if (!len)
{
INF("Client %d connection closed.", client->id);
goto client_close;
}
if (len < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
WRN("No data to read but the message handler was called.");
return;
}
WRN("Error when reading message from client: \"%s\"",
strerror(errno));
// FIXME: Should we close the connection, or just send an ERROR
// message?
goto client_close;
}
if (!client->msg.reading)
_client_msg_allocate_buf(client, msgsize);
else
_client_msg_read(client, len);
return;
client_close:
if (client->msg.reading)
_client_msg_free(client);
cserve2_client_del(client);
}
void
cserve2_client_deliver(Client *client)
{
size_t sent, size;
const char *str;
if (!client->msg.pending)
{
Fd_Flags cur_flags;
cserve2_fd_watch_flags_get(client->socket, &cur_flags);
cur_flags ^= FD_WRITE;
cserve2_fd_watch_flags_set(client->socket, cur_flags);
return;
}
size = eina_binbuf_length_get(client->msg.pending);
str = (const char *)eina_binbuf_string_get(client->msg.pending);
sent = cserve2_client_write(client, str, size);
if (sent == size)
{
eina_binbuf_free(client->msg.pending);
client->msg.pending = NULL;
return;
}
eina_binbuf_remove(client->msg.pending, 0, sent);
}
ssize_t
cserve2_client_send(Client *client, const void *data, size_t size)
{
ssize_t sent;
debug_msg("sent", data, size);
if (client->msg.pending)
{
eina_binbuf_append_length
(client->msg.pending, (unsigned char *)data, size);
return size;
}
sent = cserve2_client_write(client, data, size);
if ((sent < 0) && ((errno != EAGAIN) && (errno != EWOULDBLOCK)))
{
// FIXME: Big error when writing on the socket to the client,
// so we must close the connection to the client and remove
// its references inside our cache.
WRN("Error on socket with client %d: %s", client->id, strerror(errno));
if (client->msg.reading)
_client_msg_free(client);
cserve2_client_del(client);
return sent;
}
if (sent < 0)
sent = 0;
if (sent < (int)size)
{
Fd_Flags cur_flags;
client->msg.pending = eina_binbuf_new();
eina_binbuf_append_length
(client->msg.pending, (unsigned char *)data + sent, size - sent);
cserve2_fd_watch_flags_get(client->socket, &cur_flags);
cur_flags |= FD_WRITE;
cserve2_fd_watch_flags_set(client->socket, cur_flags);
}
return size;
}

View File

@ -0,0 +1,147 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "evas_cserve2.h"
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
struct _Shm_Mapping
{
const char *name;
size_t length;
Eina_Inlist *segments;
};
typedef struct _Shm_Mapping Shm_Mapping;
struct _Shm_Handle
{
EINA_INLIST;
Shm_Mapping *mapping;
off_t map_offset;
off_t image_offset;
size_t map_size;
size_t image_size;
};
static int id = 0;
Shm_Handle *
cserve2_shm_request(size_t size)
{
Shm_Mapping *map;
Shm_Handle *shm;
char shmname[NAME_MAX];
size_t map_size;
long pagesize;
int fd;
map = calloc(1, sizeof(Shm_Mapping));
if (!map)
{
ERR("Failed to allocate mapping handler.");
return NULL;
}
do {
snprintf(shmname, sizeof(shmname), "/evas-shm-img-%d", id++);
fd = shm_open(shmname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd == -1 && errno != EEXIST)
{
ERR("Failed to create shared memory object '%s': %m", shmname);
free(map);
return NULL;
}
} while (fd == -1);
pagesize = sysconf(_SC_PAGESIZE);
if (pagesize < 1)
{
ERR("sysconf() reported weird value for PAGESIZE, assuming 4096.");
pagesize = 4096;
}
map_size = ((size + pagesize - 1) / pagesize) * pagesize;
if (ftruncate(fd, map_size) == -1)
{
ERR("Failed to set size of shared file: %m");
close(fd);
free(map);
return NULL;
}
close(fd);
map->name = eina_stringshare_add(shmname);
map->length = map_size;
shm = calloc(1, sizeof(Shm_Handle));
if (!shm)
{
ERR("Failed to allocate shared memory handler.");
eina_stringshare_del(map->name);
free(map);
return NULL;
}
map->segments = eina_inlist_append(map->segments, EINA_INLIST_GET(shm));
shm->mapping = map;
shm->map_offset = 0;
shm->image_offset = 0;
shm->image_size = size;
shm->map_size = map_size;
return shm;
}
void
cserve2_shm_unref(Shm_Handle *shm)
{
Shm_Mapping *map = shm->mapping;
map->segments = eina_inlist_remove(map->segments, EINA_INLIST_GET(shm));
free(shm);
if (map->segments)
return;
shm_unlink(map->name);
eina_stringshare_del(map->name);
free(map);
}
const char *
cserve2_shm_name_get(const Shm_Handle *shm)
{
return shm->mapping->name;
}
off_t
cserve2_shm_map_offset_get(const Shm_Handle *shm)
{
return shm->map_offset;
}
off_t
cserve2_shm_offset_get(const Shm_Handle *shm)
{
return shm->image_offset;
}
size_t
cserve2_shm_map_size_get(const Shm_Handle *shm)
{
return shm->map_size;
}
size_t
cserve2_shm_size_get(const Shm_Handle *shm)
{
return shm->image_size;
}

View File

@ -0,0 +1,480 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
static Eina_Hash *loaders = NULL;
static Eina_List *modules = NULL;
struct ext_loader_s
{
unsigned int length;
const char *extension;
const char *loader;
};
#define MATCHING(Ext, Module) \
{ sizeof (Ext), Ext, Module }
static const struct ext_loader_s map_loaders[] =
{ /* map extensions to loaders to use for good first-guess tries */
MATCHING(".png", "png"),
MATCHING(".jpg", "jpeg"),
MATCHING(".jpeg", "jpeg"),
MATCHING(".jfif", "jpeg"),
MATCHING(".eet", "eet"),
MATCHING(".edj", "eet"),
MATCHING(".eap", "eet"),
MATCHING(".edb", "edb"),
MATCHING(".xpm", "xpm"),
MATCHING(".tiff", "tiff"),
MATCHING(".tif", "tiff"),
MATCHING(".svg", "svg"),
MATCHING(".svgz", "svg"),
MATCHING(".svg.gz", "svg"),
MATCHING(".gif", "gif"),
MATCHING(".pbm", "pmaps"),
MATCHING(".pgm", "pmaps"),
MATCHING(".ppm", "pmaps"),
MATCHING(".pnm", "pmaps"),
MATCHING(".bmp", "bmp"),
MATCHING(".tga", "tga"),
MATCHING(".wbmp", "wbmp"),
MATCHING(".ico", "ico"),
MATCHING(".cur", "ico"),
MATCHING(".psd", "psd")
};
static const char *loaders_name[] =
{ /* in order of most likely needed */
"png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "pmaps", "bmp", "tga", "wbmp", "ico", "psd", "edb"
};
Eina_Bool
evas_cserve2_loader_register(Evas_Loader_Module_Api *api)
{
eina_hash_direct_add(loaders, api->type, api);
return EINA_TRUE;
}
#if defined(__CEGCC__) || defined(__MINGW32CE__)
# define EVAS_MODULE_NAME_IMAGE_LOADER "loader_%s.dll"
#elif _WIN32
# define EVAS_MODULE_NAME_IMAGE_LOADER "module.dll"
#else
# define EVAS_MODULE_NAME_IMAGE_LOADER "module.so"
#endif
static Evas_Loader_Module_Api *
loader_module_find(const char *type)
{
Evas_Loader_Module_Api *l;
Eina_Module *em;
char buf[PATH_MAX];
l = eina_hash_find(loaders, type);
if (l) return l;
/* FIXME: Look in every possible path, but what will those be? */
snprintf(buf, sizeof(buf), PACKAGE_LIB_DIR "/evas/cserve2/loaders/%s/%s/%s",
type, MODULE_ARCH, EVAS_MODULE_NAME_IMAGE_LOADER);
em = eina_module_new(buf);
if (!em) return NULL;
if (!eina_module_load(em))
{
eina_module_free(em);
return NULL;
}
l = eina_hash_find(loaders, type);
if (l)
{
modules = eina_list_append(modules, em);
return l;
}
eina_module_free(em);
return NULL;
}
static Eina_Bool
command_read(int fd, Slave_Command *cmd, void **params)
{
ssize_t ret;
int ints[2], size, got = 0;
char *buf;
ret = read(fd, ints, sizeof(int) * 2);
if (ret < (int)sizeof(int) * 2)
return EINA_FALSE;
size = ints[0];
buf = malloc(size);
if (!buf) return EINA_FALSE;
do {
ret = read(fd, buf + got, size - got);
if (ret < 0)
{
/* EINTR means we were interrupted by a signal before anything
* was sent, and if we are back here it means that signal was
* not meant for us to die. Any other error here is fatal and
* should result in the slave terminating.
*/
if (errno == EINTR)
continue;
free(buf);
return EINA_FALSE;
}
got += ret;
} while (got < size);
*cmd = ints[1];
*params = buf;
return EINA_TRUE;
}
static Eina_Bool
response_send(int fd, Slave_Command cmd, void *resp, int size)
{
int sent = 0, ints[2];
const char *data = resp;
ssize_t ret;
ints[0] = size;
ints[1] = cmd;
ret = write(fd, ints, sizeof(int) * 2);
if (ret < 0)
return EINA_FALSE;
if (!size)
return EINA_TRUE;
do {
ret = write(fd, data + sent, size - sent);
if (ret < 0)
{
/* EINTR means we were interrupted by a signal before anything
* was sent, and if we are back here it means that signal was
* not meant for us to die. Any other error here is fatal and
* should result in the slave terminating.
*/
if (errno == EINTR)
continue;
return EINA_FALSE;
}
sent += ret;
} while (sent < size);
return EINA_TRUE;
}
static Eina_Bool
error_send(int fd, Error_Type err)
{
return response_send(fd, ERROR, &err, sizeof(Error_Type));
}
void *
cserve2_shm_map(const char *name, size_t length, off_t offset)
{
void *map;
int fd;
fd = shm_open(name, O_RDWR, S_IWUSR);
if (fd == -1)
return MAP_FAILED;
map = mmap(NULL, length, PROT_WRITE, MAP_SHARED, fd, offset);
close(fd);
return map;
}
void
cserve2_shm_unmap(void *map, size_t length)
{
munmap(map, length);
}
static Error_Type
image_open(const char *file, const char *key, Image_Load_Opts *opts, Slave_Msg_Image_Opened *result, const char **use_loader)
{
Evas_Img_Load_Params ilp;
Evas_Loader_Module_Api *api;
const char *loader = NULL, *end;
unsigned int i;
int len;
int err;
memset(&ilp, 0, sizeof(ilp));
if (opts)
{
#define SETOPT(v) ilp.opts.v = opts->v
SETOPT(w);
SETOPT(h);
SETOPT(rx);
SETOPT(ry);
SETOPT(rw);
SETOPT(rh);
SETOPT(scale_down_by);
SETOPT(dpi);
SETOPT(orientation);
#undef SETOPT
ilp.has_opts = EINA_TRUE;
}
if (!*use_loader)
goto try_extension;
loader = *use_loader;
api = loader_module_find(loader);
if (!api)
goto try_extension;
if (api->head_load(&ilp, file, key, &err))
goto done;
try_extension:
len = strlen(file);
end = file + len;
for (i = 0; i < (sizeof (map_loaders) / sizeof(struct ext_loader_s)); i++)
{
int len2 = strlen(map_loaders[i].extension);
if (len2 > len) continue;
if (!strcasecmp(end - len2, map_loaders[i].extension))
{
loader = map_loaders[i].loader;
break;
}
}
if (!loader)
goto try_all_known;
api = loader_module_find(loader);
if (!api)
goto try_all_known;
if (api->head_load(&ilp, file, key, &err))
goto done;
try_all_known:
for (i = 0; i < (sizeof(loaders_name) / sizeof(loaders_name[0])); i++)
{
loader = loaders_name[i];
api = loader_module_find(loader);
if (!api)
continue;
if (api->head_load(&ilp, file, key, &err))
goto done;
}
/* find every module available and try them, even if we don't know they
* exist. That will be our generic loader */
return err;
done:
*use_loader = loader;
result->w = ilp.w;
result->h = ilp.h;
if ((result->rotated = ilp.rotated))
{
result->degree = ilp.degree;
}
if ((result->animated = ilp.animated))
{
result->frame_count = ilp.frame_count;
result->loop_count = ilp.loop_count;
result->loop_hint = ilp.loop_hint;
}
result->scale = ilp.scale;
result->alpha = ilp.alpha;
return CSERVE2_NONE;
}
static Error_Type
image_load(const char *file, const char *key, const char *shmfile, Slave_Msg_Image_Load *params, Slave_Msg_Image_Loaded *result, const char *loader)
{
Evas_Img_Load_Params ilp;
Evas_Loader_Module_Api *api;
int err;
Error_Type ret = CSERVE2_NONE;
char *map = cserve2_shm_map(shmfile, params->shm.mmap_size,
params->shm.mmap_offset);
if (map == MAP_FAILED)
return CSERVE2_RESOURCE_ALLOCATION_FAILED;
memset(&ilp, 0, sizeof(ilp));
api = loader_module_find(loader);
if (!api)
{
ret = CSERVE2_GENERIC;
goto done;
}
ilp.w = params->w;
ilp.h = params->h;
ilp.alpha = params->alpha;
#define SETOPT(v) ilp.opts.v = params->opts.v
SETOPT(w);
SETOPT(h);
SETOPT(rx);
SETOPT(ry);
SETOPT(rw);
SETOPT(rh);
SETOPT(scale_down_by);
SETOPT(dpi);
SETOPT(orientation);
#undef SETOPT
ilp.buffer = map + params->shm.image_offset;
if (!api->data_load(&ilp, file, key, &err))
ret = err;
result->alpha_sparse = ilp.alpha_sparse;
done:
cserve2_shm_unmap(map, params->shm.mmap_size);
return ret;
}
static void
handle_image_open(int wfd, void *params)
{
Slave_Msg_Image_Open *p;
Slave_Msg_Image_Opened result;
Image_Load_Opts *load_opts = NULL;
Error_Type err;
const char *loader = NULL, *file, *key, *ptr;
char *resp;
size_t resp_size;
p = params;
file = (const char *)(p + sizeof(Slave_Msg_Image_Open));
key = file + strlen(file) + 1;
ptr = key + strlen(key) + 1;
if (p->has_opts)
{
load_opts = (Image_Load_Opts *)ptr;
ptr += sizeof(Image_Load_Opts);
}
if (p->has_loader_data)
loader = ptr;
memset(&result, 0, sizeof(result));
if ((err = image_open(file, key, load_opts, &result, &loader))
!= CSERVE2_NONE)
{
error_send(wfd, err);
return;
}
result.has_loader_data = EINA_TRUE;
resp_size = sizeof(Slave_Msg_Image_Opened) + sizeof(int) + strlen(loader) + 1;
resp = alloca(resp_size);
memcpy(resp, &result, sizeof(Slave_Msg_Image_Opened));
memcpy(resp + sizeof(Slave_Msg_Image_Opened), loader, strlen(loader) + 1);
response_send(wfd, IMAGE_OPEN, resp, resp_size);
}
static void
handle_image_load(int wfd, void *params)
{
Slave_Msg_Image_Load *load_args = params;
Slave_Msg_Image_Loaded resp;
Error_Type err;
const char *shmfile;
const char *file, *key, *loader;
if (!load_args->has_loader_data)
{
error_send(wfd, CSERVE2_UNKNOWN_FORMAT);
return;
}
memset(&resp, 0, sizeof(resp));
shmfile = ((const char *)params) + sizeof(Slave_Msg_Image_Load);
file = shmfile + strlen(shmfile) + 1;
key = file + strlen(file) + 1;
loader = key + strlen(key) + 1;
if ((err = image_load(file, key, shmfile, load_args, &resp, loader))
!= CSERVE2_NONE)
{
error_send(wfd, err);
return;
}
response_send(wfd, IMAGE_LOAD, &resp, sizeof(resp));
}
int main(int c, char **v)
{
int wfd, rfd;
Slave_Command cmd;
void *params = NULL;
Eina_Module *m;
Eina_Bool quit = EINA_FALSE;
if (c < 3)
return 1;
eina_init();
loaders = eina_hash_string_superfast_new(NULL);
wfd = atoi(v[1]);
rfd = atoi(v[2]);
while (!quit)
{
if (!command_read(rfd, &cmd, &params))
{
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;
}

View File

@ -0,0 +1,86 @@
#ifndef _EVAS_CSERVE2_SLAVE_H
#define _EVAS_CSERVE2_SLAVE_H
#include <Evas.h>
/* begin bunch of stuff from evas_common.h so that we don't need to drag
* a lot of useless @SOMETHING_CFLAGS@ around */
typedef unsigned long long DATA64;
typedef unsigned int DATA32;
typedef unsigned short DATA16;
typedef unsigned char DATA8;
#ifndef WORDS_BIGENDIAN
/* x86 */
#define A_VAL(p) (((DATA8 *)(p))[3])
#define R_VAL(p) (((DATA8 *)(p))[2])
#define G_VAL(p) (((DATA8 *)(p))[1])
#define B_VAL(p) (((DATA8 *)(p))[0])
#define AR_VAL(p) ((DATA16 *)(p)[1])
#define GB_VAL(p) ((DATA16 *)(p)[0])
#else
/* ppc */
#define A_VAL(p) (((DATA8 *)(p))[0])
#define R_VAL(p) (((DATA8 *)(p))[1])
#define G_VAL(p) (((DATA8 *)(p))[2])
#define B_VAL(p) (((DATA8 *)(p))[3])
#define AR_VAL(p) ((DATA16 *)(p)[0])
#define GB_VAL(p) ((DATA16 *)(p)[1])
#endif
/* if more than 1/ALPHA_SPARSE_INV_FRACTION is "alpha" (1-254) then sparse
* alpha flag gets set */
#define ALPHA_SPARSE_INV_FRACTION 3
#define IMG_MAX_SIZE 65000
#define IMG_TOO_BIG(w, h) \
((((unsigned long long)w) * ((unsigned long long)h)) >= \
((1ULL << (29 * (sizeof(void *) / 4))) - 2048))
#define RGB_JOIN(r,g,b) \
(((r) << 16) + ((g) << 8) + (b))
#define ARGB_JOIN(a,r,g,b) \
(((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
/* end bunchf of stuff from evas_common.h */
typedef struct _Evas_Loader_Module_Api Evas_Loader_Module_Api;
typedef struct _Evas_Img_Load_Params Evas_Img_Load_Params;
#define EVAS_CSERVE2_MODULE_API_VERSION 1
struct _Evas_Loader_Module_Api {
int version;
const char *type;
Eina_Bool (*head_load)(Evas_Img_Load_Params *p, const char *file, const char *key, int *error);
Eina_Bool (*data_load)(Evas_Img_Load_Params *p, const char *file, const char *key, int *error);
};
struct _Evas_Img_Load_Params {
unsigned int w, h;
unsigned int degree;
unsigned int scale;
int frame_count;
int loop_count;
int loop_hint;
struct {
unsigned int w, h;
unsigned int rx, ry, rw, rh;
int scale_down_by;
double dpi;
Eina_Bool orientation;
} opts;
void *buffer;
Eina_Bool has_opts : 1;
Eina_Bool rotated : 1;
Eina_Bool alpha : 1;
Eina_Bool alpha_sparse : 1;
Eina_Bool animated : 1;
};
EAPI Eina_Bool evas_cserve2_loader_register(Evas_Loader_Module_Api *api);
EAPI void evas_cserve2_image_premul(Evas_Img_Load_Params *ilp);
EAPI void evas_cserve2_image_alpha_sparse_set(Evas_Img_Load_Params *ilp);
#endif /* _EVAS_CSERVE2_SLAVE_H */

View File

@ -0,0 +1,395 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "evas_cserve2.h"
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
struct _Slave_Proc
{
pid_t pid;
const char *name;
int write_fd;
int read_fd;
Slave_Read_Cb read_cb;
Slave_Dead_Cb dead_cb;
const void *data;
Eina_Binbuf *pending;
struct {
int size;
int read_size;
Slave_Command cmd;
char *buf;
} read;
Eina_Bool killed : 1;
};
static Eina_List *slaves;
static Slave_Proc *
_child_find(pid_t pid)
{
Eina_List *l;
Slave_Proc *s;
EINA_LIST_FOREACH(slaves, l, s)
if (s->pid == pid)
return s;
return NULL;
}
static void
_slave_free(Slave_Proc *s)
{
if (s->write_fd)
close(s->write_fd);
if (s->read_fd)
{
cserve2_fd_watch_del(s->read_fd);
close(s->read_fd);
}
free(s->read.buf);
if (s->pending)
eina_binbuf_free(s->pending);
if (s->dead_cb)
s->dead_cb(s, (void *)s->data);
eina_stringshare_del(s->name);
free(s);
}
static void
_slave_dead_cb(int pid, int status __UNUSED__)
{
Slave_Proc *s;
DBG("Child dead with pid '%d'.", pid);
s = _child_find(pid);
if (!s)
{
ERR("Unknown child dead '%d'.", pid);
return;
}
slaves = eina_list_remove(slaves, s);
_slave_free(s);
}
static size_t
_slave_write(Slave_Proc *s, const char *data, size_t size)
{
size_t sent = 0;
do
{
ssize_t ret;
ret = write(s->write_fd, data + sent, size - sent);
if (ret == -1)
{
if (errno == EAGAIN)
break;
if (errno == EPIPE)
{
WRN("Slave unexpectedly gone.");
/* handle dead? */
break;
}
}
sent += ret;
} while(sent < size);
return sent;
}
static void
_slave_write_cb(int fd __UNUSED__, Fd_Flags flags __UNUSED__, void *data)
{
Slave_Proc *s = data;
size_t sent;
size_t size;
const char *str;
size = eina_binbuf_length_get(s->pending);
str = (const char *)eina_binbuf_string_get(s->pending);
sent = _slave_write(s, str, size);
if (sent == size)
{
eina_binbuf_free(s->pending);
s->pending = NULL;
cserve2_fd_watch_del(s->write_fd);
return;
}
eina_binbuf_remove(s->pending, 0, sent);
}
static void
_slave_read_clear(Slave_Proc *s)
{
s->read.buf = NULL;
s->read.cmd = 0;
s->read.read_size = s->read.size = 0;
}
static void
_slave_read_cb(int fd, Fd_Flags flags, void *data)
{
Slave_Proc *s = data;
Eina_Bool done = EINA_FALSE;
/* handle error */
if (!(flags & FD_READ))
return;
if (!s->read.size)
{
int ints[2];
ssize_t ret;
ret = read(fd, ints, sizeof(int) * 2);
if (ret < (int)sizeof(int) * 2)
{
return;
}
s->read.size = ints[0];
s->read.cmd = ints[1];
if (s->read.size)
s->read.buf = malloc(s->read.size);
else
done = EINA_TRUE;
}
if (s->read.buf)
{
ssize_t ret;
do {
char *p = s->read.buf + s->read.read_size;
int sz = s->read.size - s->read.read_size;
ret = read(fd, p, sz);
if (ret < 0)
{
if (errno == EAGAIN)
break;
}
s->read.read_size += ret;
} while(s->read.read_size < s->read.size);
if (s->read.read_size == s->read.size)
done = EINA_TRUE;
}
if (done)
{
s->read_cb(s, s->read.cmd, s->read.buf, (void *)s->data);
_slave_read_clear(s);
}
}
Eina_Bool
cserve2_slaves_init(void)
{
cserve2_on_child_dead_set(_slave_dead_cb);
return EINA_TRUE;
}
void
cserve2_slaves_shutdown(void)
{
Slave_Proc *s;
cserve2_on_child_dead_set(NULL);
if (!slaves)
return;
DBG("Shutting down slaves subsystem with %d slaves alive!",
eina_list_count(slaves));
EINA_LIST_FREE(slaves, s)
{
kill(s->pid, SIGKILL);
_slave_free(s);
}
}
static const char *
_slave_path_get(const char *name)
{
char buf[PATH_MAX], cwd[PATH_MAX];
struct stat st;
if (name[0] == '/')
{
if (access(name, X_OK))
return NULL;
return eina_stringshare_add(name);
}
getcwd(cwd, sizeof(cwd));
snprintf(buf, sizeof(buf), "%s/%s", cwd, name);
if (!access(buf, X_OK))
return eina_stringshare_add(buf);
snprintf(buf, sizeof(buf), PACKAGE_LIBEXEC_DIR"/%s", name);
if (!access(buf, X_OK))
return eina_stringshare_add(buf);
return NULL;
}
Slave_Proc *
cserve2_slave_run(const char *exe, Slave_Read_Cb read_cb, Slave_Dead_Cb dead_cb, const void *data)
{
Slave_Proc *s;
pid_t pid;
int child[2], parent[2];
int flags;
const char *name;
name = _slave_path_get(exe);
if (!name)
{
ERR("Cannot execute slave '%s'. Not found or not executable.", exe);
return NULL;
}
DBG("Running slave '%s', resolved to path: %s", exe, name);
s = calloc(1, sizeof(Slave_Proc));
if (!s)
{
ERR("Could not create Slave_Proc handler.");
eina_stringshare_del(name);
return NULL;
}
if (pipe(child))
{
ERR("Could not create pipes for child.");
eina_stringshare_del(name);
free(s);
return NULL;
}
if (pipe(parent))
{
ERR("Could not create pipes for parent.");
eina_stringshare_del(name);
free(s);
close(child[0]);
close(child[1]);
return NULL;
}
pid = fork();
if (pid < 0)
{
ERR("Could not create sub process.");
eina_stringshare_del(name);
close(child[0]);
close(child[1]);
close(parent[0]);
close(parent[1]);
free(s);
return NULL;
}
if (!pid)
{
char *args[4], readfd[12], writefd[12];
close(child[1]);
close(parent[0]);
sprintf(readfd, "%d", child[0]);
sprintf(writefd, "%d", parent[1]);
args[0] = (char *)name;
args[1] = writefd;
args[2] = readfd;
args[3] = NULL;
execvp(name, args);
/* we only get here if execvp fails, which should not
* happen and if it does, it's baaaaaaaaad */
ERR("execvp() for slave at: '%s' failed! '%m'", name);
exit(1);
}
s->pid = pid;
s->name = name;
s->write_fd = child[1];
flags = fcntl(s->write_fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(s->write_fd, F_SETFL, flags);
s->read_fd = parent[0];
flags = fcntl(s->read_fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(s->read_fd, F_SETFL, flags);
s->read_cb = read_cb;
s->dead_cb = dead_cb;
s->data = data;
cserve2_fd_watch_add(s->read_fd, FD_READ, _slave_read_cb, s);
close(child[0]);
close(parent[1]);
slaves = eina_list_append(slaves, s);
return s;
}
static void
_slave_send_aux(Slave_Proc *s, const char *data, size_t size)
{
size_t sent;
if (s->pending)
{
eina_binbuf_append_length(s->pending, (unsigned char *)data, size);
return;
}
sent = _slave_write(s, data, size);
if (sent < size)
{
s->pending = eina_binbuf_new();
eina_binbuf_append_length(s->pending, (unsigned char *)data + sent,
size - sent);
cserve2_fd_watch_add(s->write_fd, FD_WRITE, _slave_write_cb, s);
}
}
void
cserve2_slave_send(Slave_Proc *s, Slave_Command cmd, const char *data, size_t size)
{
int ints[2];
ints[0] = size;
ints[1] = cmd;
_slave_send_aux(s, (char *)ints, sizeof(int) * 2);
if (size)
_slave_send_aux(s, (char *)data, size);
}
void
cserve2_slave_kill(Slave_Proc *s)
{
if (s->killed)
{
if (!kill(s->pid, 0))
DBG("Slave %p(%d) requested to kill, but it's still alive.",
s, s->pid);
}
s->killed = EINA_TRUE;
kill(s->pid, SIGTERM);
}

View File

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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -0,0 +1,158 @@
#ifdef HAVE_CONFIG_H
# include "config.h" /* so that EAPI in Eet.h is correctly defined */
#endif
#include <Eet.h>
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
static Eina_Bool
evas_image_load_file_head_eet(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
{
int alpha, compression, quality, lossy;
unsigned int w, h;
Eet_File *ef;
int ok;
Eina_Bool res = EINA_FALSE;
if (!key)
{
*error = CSERVE2_DOES_NOT_EXIST;
return EINA_FALSE;
}
ef = eet_open((char *)file, EET_FILE_MODE_READ);
if (!ef)
{
*error = CSERVE2_DOES_NOT_EXIST;
return EINA_FALSE;
}
ok = eet_data_image_header_read(ef, key,
&w, &h, &alpha, &compression, &quality, &lossy);
if (!ok)
{
*error = CSERVE2_DOES_NOT_EXIST;
goto on_error;
}
if (IMG_TOO_BIG(w, h))
{
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
goto on_error;
}
if (alpha) ilp->alpha = 1;
ilp->w = w;
ilp->h = h;
res = EINA_TRUE;
*error = CSERVE2_NONE;
on_error:
eet_close(ef);
return res;
}
Eina_Bool
evas_image_load_file_data_eet(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
{
unsigned int w, h;
int alpha, compression, quality, lossy, ok;
Eet_File *ef;
DATA32 *body, *p, *end, *data;
DATA32 nas = 0;
Eina_Bool res = EINA_FALSE;
if (!key)
{
*error = CSERVE2_DOES_NOT_EXIST;
return EINA_FALSE;
}
ef = eet_open(file, EET_FILE_MODE_READ);
if (!ef)
{
*error = CSERVE2_DOES_NOT_EXIST;
return EINA_FALSE;
}
ok = eet_data_image_header_read(ef, key,
&w, &h, &alpha, &compression, &quality, &lossy);
if (IMG_TOO_BIG(w, h))
{
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
goto on_error;
}
if (!ok)
{
*error = CSERVE2_DOES_NOT_EXIST;
goto on_error;
}
data = ilp->buffer;
if (!data)
{
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
goto on_error;
}
ok = eet_data_image_read_to_surface(ef, key, 0, 0,
data, w, h, w * 4,
&alpha, &compression, &quality, &lossy);
if (!ok)
{
*error = CSERVE2_GENERIC;
goto on_error;
}
if (alpha)
{
ilp->alpha = 1;
body = ilp->buffer;
end = body + (w * h);
for (p = body; p < end; p++)
{
DATA32 r, g, b, a;
a = A_VAL(p);
r = R_VAL(p);
g = G_VAL(p);
b = B_VAL(p);
if ((a == 0) || (a == 255)) nas++;
if (r > a) r = a;
if (g > a) g = a;
if (b > a) b = a;
*p = ARGB_JOIN(a, r, g, b);
}
if ((ALPHA_SPARSE_INV_FRACTION * nas) >= (w * h))
ilp->alpha_sparse = 1;
}
*error = CSERVE2_NONE;
res = EINA_TRUE;
on_error:
eet_close(ef);
return res;
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"eet",
evas_image_load_file_head_eet,
evas_image_load_file_data_eet
};
static Eina_Bool
module_init(void)
{
eet_init();
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
eet_shutdown();
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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

View File

@ -0,0 +1,789 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
static Eina_Bool
read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
{
unsigned char b[2];
if (*position + 2 > length) return EINA_FALSE;
b[0] = map[(*position)++];
b[1] = map[(*position)++];
*ret = (b[1] << 8) | b[0];
return EINA_TRUE;
}
static Eina_Bool
read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
{
unsigned char b[4];
unsigned int i;
if (*position + 4 > length) return EINA_FALSE;
for (i = 0; i < 4; i++)
b[i] = map[(*position)++];
*ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
return EINA_TRUE;
}
static Eina_Bool
read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
{
if (*position + 1 > length) return EINA_FALSE;
*ret = map[(*position)++];
return EINA_TRUE;
}
static Eina_Bool
read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
{
if (*position + size > length) return EINA_FALSE;
memcpy(buffer, map + *position, size);
*position += size;
return EINA_TRUE;
}
enum
{
SMALLEST,
BIGGEST,
SMALLER,
BIGGER
};
enum
{
ICON = 1,
CURSOR = 2
};
static Eina_Bool
evas_image_load_file_head_ico(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
{
Eina_File *f;
void *map = NULL;
size_t position = 0;
unsigned short word;
unsigned char byte;
int wanted_w = 0, wanted_h = 0, w, h, cols, i, planes = 0,
bpp = 0, pdelta, search = -1, have_choice = 0,
hasa = 1;
unsigned int bmoffset, bmsize, fsize;
unsigned short reserved, type, count;
struct {
int pdelta;
int w, h;
int cols;
int bpp, planes;
int hot_x, hot_y;
unsigned int bmoffset, bmsize;
} chosen = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
f = eina_file_open(file, EINA_FALSE);
if (!f)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
fsize = eina_file_size_get(f);
if (fsize < (6 + 16 + 40)) goto close_file;
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
if (!map) goto close_file;
// key:
// NULL == highest res
// biggest == highest res
// smallest == lowest res
//
// smaller == next size SMALLER than load opts WxH (if possible)
// bigger == next size BIGGER than load opts WxH (if possible)
// more ?
search = BIGGEST;
if ((ilp->opts.w > 0) && (ilp->opts.h > 0))
{
wanted_w = ilp->opts.w;
wanted_h = ilp->opts.h;
search = SMALLER;
}
if (!read_ushort(map, fsize, &position, &reserved)) goto close_file;
if (!read_ushort(map, fsize, &position, &type)) goto close_file;
if (!read_ushort(map, fsize, &position, &count)) goto close_file;
if (!((reserved == 0) &&
((type == ICON) || (type == CURSOR)) && (count > 0)))
goto close_file;
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
if (key)
{
if (!strcmp(key, "biggest"))
{
wanted_w = 0;
wanted_h = 0;
search = BIGGEST;
chosen.pdelta = 0;
}
else if (!strcmp(key, "smallest"))
{
wanted_w = 1;
wanted_h = 1;
search = SMALLEST;
chosen.pdelta = 0x7fffffff;
}
else if (!strcmp(key, "smaller"))
{
chosen.pdelta = 0x7fffffff;
search = SMALLER;
}
else if (!strcmp(key, "bigger"))
{
chosen.pdelta = 0x7fffffff;
search = BIGGER;
}
}
for (i = 0; i < count; i++)
{
unsigned char tw = 0, th = 0, tcols = 0;
if (!read_uchar(map, fsize, &position, &tw)) goto close_file;
w = tw;
if (w <= 0) w = 256;
if (!read_uchar(map, fsize, &position, &th)) goto close_file;
h = th;
if (h <= 0) h = 256;
if (!read_uchar(map, fsize, &position, &tcols)) goto close_file;
cols = tcols;
if (cols <= 0) cols = 256;
if (!read_uchar(map, fsize, &position, &byte)) goto close_file;
if (!read_ushort(map, fsize, &position, &word)) goto close_file;
if (type == CURSOR) planes = word;
//else hot_x = word;
if (!read_ushort(map, fsize, &position, &word)) goto close_file;
if (type == CURSOR) bpp = word;
//else hot_y = word;
if (!read_uint(map, fsize, &position, &bmsize)) goto close_file;
if (!read_uint(map, fsize, &position, &bmoffset)) goto close_file;
if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize)) goto close_file;
if (search == BIGGEST)
{
pdelta = w * h;
if ((!have_choice) ||
((pdelta >= chosen.pdelta) &&
(((bpp >= 3) && (bpp >= chosen.bpp)) ||
((bpp < 3) && (cols >= chosen.cols)))))
{
have_choice = 1;
chosen.pdelta = pdelta;
chosen.w = w;
chosen.h = h;
chosen.cols = cols;
chosen.bpp = bpp;
chosen.planes = planes;
chosen.bmsize = bmsize;
chosen.bmoffset = bmoffset;
}
}
else
{
if (search == SMALLEST)
{
pdelta = w * h;
if ((!have_choice) ||
((pdelta <= chosen.pdelta) &&
(((bpp >= 3) && (bpp >= chosen.bpp)) ||
((bpp < 3) && (cols >= chosen.cols)))))
{
have_choice = 1;
chosen.pdelta = pdelta;
chosen.w = w;
chosen.h = h;
chosen.cols = cols;
chosen.bpp = bpp;
chosen.planes = planes;
chosen.bmsize = bmsize;
chosen.bmoffset = bmoffset;
}
}
else if (search == SMALLER)
{
pdelta = (wanted_w * wanted_h) - (w * h);
if ((!have_choice) ||
((w <= wanted_w) && (h <= wanted_h) &&
(pdelta <= chosen.pdelta) &&
(((bpp >= 3) && (bpp >= chosen.bpp)) ||
((bpp < 3) && (cols >= chosen.cols)))))
{
have_choice = 1;
if (pdelta < 0) pdelta = 0x7fffffff;
chosen.pdelta = pdelta;
chosen.w = w;
chosen.h = h;
chosen.cols = cols;
chosen.bpp = bpp;
chosen.planes = planes;
chosen.bmsize = bmsize;
chosen.bmoffset = bmoffset;
}
}
else if (search == BIGGER)
{
pdelta = (w * h) - (wanted_w * wanted_h);
if ((!have_choice) ||
((w >= wanted_w) && (h >= wanted_h) &&
(pdelta <= chosen.pdelta) &&
(((bpp >= 3) && (bpp >= chosen.bpp)) ||
((bpp < 3) && (cols >= chosen.cols)))))
{
have_choice = 1;
if (pdelta < 0) pdelta = 0x7fffffff;
chosen.pdelta = pdelta;
chosen.w = w;
chosen.h = h;
chosen.cols = cols;
chosen.bpp = bpp;
chosen.planes = planes;
chosen.bmsize = bmsize;
chosen.bmoffset = bmoffset;
}
}
}
}
if (chosen.bmoffset == 0) goto close_file;
position = chosen.bmoffset;
w = chosen.w;
h = chosen.h;
if ((w > 256) || (h > 256)) goto close_file;
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
{
if (IMG_TOO_BIG(w, h))
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
else
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
ilp->w = w;
ilp->h = h;
if (hasa) ilp->alpha = 1;
eina_file_map_free(f, map);
eina_file_close(f);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
close_file:
if (map) eina_file_map_free(f, map);
eina_file_close(f);
return EINA_FALSE;
}
static Eina_Bool
evas_image_load_file_data_ico(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
{
Eina_File *f;
void *map = NULL;
size_t position = 0;
unsigned short word;
unsigned char byte;
unsigned int dword;
int wanted_w = 0, wanted_h = 0, w, h, cols, i, planes = 0,
bpp = 0, pdelta, search = -1, have_choice = 0,
stride, pstride, j, right_way_up = 0, diff_size = 0, cols2;
unsigned int bmoffset, bmsize, bitcount, fsize,
*pal, *surface, *pix, none_zero_alpha = 0;
unsigned short reserved, type, count;
unsigned char *maskbuf, *pixbuf, *p;
struct {
int pdelta;
int w, h;
int cols;
int bpp, planes;
int hot_x, hot_y;
unsigned int bmoffset, bmsize;
} chosen = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
f = eina_file_open(file, EINA_FALSE);
if (!f)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
fsize = eina_file_size_get(f);
if (fsize < (6 + 16 + 40)) goto close_file;
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
if (!map) goto close_file;
// key:
// NULL == highest res
// biggest == highest res
// smallest == lowest res
//
// smaller == next size SMALLER than load opts WxH (if possible)
// bigger == next size BIGGER than load opts WxH (if possible)
// more ?
search = BIGGEST;
if ((ilp->opts.w > 0) && (ilp->opts.h > 0))
{
wanted_w = ilp->opts.w;
wanted_h = ilp->opts.h;
search = SMALLER;
}
if (!read_ushort(map, fsize, &position, &reserved)) goto close_file;
if (!read_ushort(map, fsize, &position, &type)) goto close_file;
if (!read_ushort(map, fsize, &position, &count)) goto close_file;
if (!((reserved == 0) &&
((type == ICON) || (type == CURSOR)) && (count > 0)))
goto close_file;
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
if (key)
{
if (!strcmp(key, "biggest"))
{
wanted_w = 0;
wanted_h = 0;
search = BIGGEST;
chosen.pdelta = 0;
}
else if (!strcmp(key, "smallest"))
{
wanted_w = 1;
wanted_h = 1;
search = SMALLEST;
chosen.pdelta = 0x7fffffff;
}
else if (!strcmp(key, "smaller"))
{
chosen.pdelta = 0x7fffffff;
search = SMALLER;
}
else if (!strcmp(key, "bigger"))
{
chosen.pdelta = 0x7fffffff;
search = BIGGER;
}
}
for (i = 0; i < count; i++)
{
unsigned char tw = 0, th = 0, tcols = 0;
if (!read_uchar(map, fsize, &position, &tw)) goto close_file;
w = tw;
if (w <= 0) w = 256;
if (!read_uchar(map, fsize, &position, &th)) goto close_file;
h = th;
if (h <= 0) h = 256;
if (!read_uchar(map, fsize, &position, &tcols)) goto close_file;
cols = tcols;
if (cols <= 0) cols = 256;
if (!read_uchar(map, fsize, &position, &byte)) goto close_file;
if (!read_ushort(map, fsize, &position, &word)) goto close_file;
if (type == 1) planes = word;
//else hot_x = word;
if (!read_ushort(map, fsize, &position, &word)) goto close_file;
if (type == 1) bpp = word;
//else hot_y = word;
if (!read_uint(map, fsize, &position, &bmsize)) goto close_file;
if (!read_uint(map, fsize, &position, &bmoffset)) goto close_file;
if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize)) goto close_file;
if (search == BIGGEST)
{
pdelta = w * h;
if ((!have_choice) ||
((pdelta >= chosen.pdelta) &&
(((bpp >= 3) && (bpp >= chosen.bpp)) ||
((bpp < 3) && (cols >= chosen.cols)))))
{
have_choice = 1;
chosen.pdelta = pdelta;
chosen.w = w;
chosen.h = h;
chosen.cols = cols;
chosen.bpp = bpp;
chosen.planes = planes;
chosen.bmsize = bmsize;
chosen.bmoffset = bmoffset;
}
}
else
{
if (search == SMALLEST)
{
pdelta = w * h;
if ((!have_choice) ||
((pdelta <= chosen.pdelta) &&
(((bpp >= 3) && (bpp >= chosen.bpp)) ||
((bpp < 3) && (cols >= chosen.cols)))))
{
have_choice = 1;
chosen.pdelta = pdelta;
chosen.w = w;
chosen.h = h;
chosen.cols = cols;
chosen.bpp = bpp;
chosen.planes = planes;
chosen.bmsize = bmsize;
chosen.bmoffset = bmoffset;
}
}
else if (search == SMALLER)
{
pdelta = (wanted_w * wanted_h) - (w * h);
if ((!have_choice) ||
((w <= wanted_w) && (h <= wanted_h) &&
(pdelta <= chosen.pdelta) &&
(((bpp >= 3) && (bpp >= chosen.bpp)) ||
((bpp < 3) && (cols >= chosen.cols)))))
{
have_choice = 1;
if (pdelta < 0) pdelta = 0x7fffffff;
chosen.pdelta = pdelta;
chosen.w = w;
chosen.h = h;
chosen.cols = cols;
chosen.bpp = bpp;
chosen.planes = planes;
chosen.bmsize = bmsize;
chosen.bmoffset = bmoffset;
}
}
else if (search == BIGGER)
{
pdelta = (w * h) - (wanted_w * wanted_h);
if ((!have_choice) ||
((w >= wanted_w) && (h >= wanted_h) &&
(pdelta <= chosen.pdelta) &&
(((bpp >= 3) && (bpp >= chosen.bpp)) ||
((bpp < 3) && (cols >= chosen.cols)))))
{
have_choice = 1;
if (pdelta < 0) pdelta = 0x7fffffff;
chosen.pdelta = pdelta;
chosen.w = w;
chosen.h = h;
chosen.cols = cols;
chosen.bpp = bpp;
chosen.planes = planes;
chosen.bmsize = bmsize;
chosen.bmoffset = bmoffset;
}
}
}
}
if (chosen.bmoffset == 0) goto close_file;
position = chosen.bmoffset;
w = chosen.w;
h = chosen.h;
cols = chosen.cols;
bpp = chosen.bpp;
// changed since we loaded header?
if (((int)ilp->w != w) || ((int)ilp->h != h)) goto close_file;
// read bmp header time... let's do some checking
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // headersize - dont care
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // width
if (dword > 0)
{
if ((int)dword != w)
{
w = dword;
diff_size = 1;
}
}
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // height
if (dword > 0)
{
if ((int)dword != (h * 2))
{
h = dword / 2;
diff_size = 1;
}
}
if (diff_size)
{
ERR("Broken ICO file: %s - "
" Reporting size of %ix%i in index, but bitmap is %ix%i. "
" May be expanded or cropped.",
file, ilp->w, ilp->h, w, h);
}
if (!read_ushort(map, fsize, &position, &word)) goto close_file; // planes
//planes2 = word;
if (!read_ushort(map, fsize, &position, &word)) goto close_file; // bitcount
bitcount = word;
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // compression
//compression = dword;
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // imagesize
//imagesize = dword;
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // z pixels per m
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // y pizels per m
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // colors used
//colorsused = dword;
if (!read_uint(map, fsize, &position, &dword)) goto close_file; // colors important
//colorsimportant = dword;
surface = ilp->buffer;
if (!surface)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
memset(surface, 0, ilp->w * ilp->h * 4);
if (!((bitcount == 1) || (bitcount == 4) || (bitcount == 8) ||
(bitcount == 24) || (bitcount == 32)))
goto close_file;
if (bitcount <= 8)
{
cols2 = 1 << bitcount;
if (cols == 0) cols = cols2;
if (cols > cols2) cols = cols2;
if (cols > 256) cols = 256;
}
else
cols = 0;
if (bitcount > 8) cols = 0;
pal = alloca(256 * 4);
for (i = 0; i < cols; i++)
{
unsigned char a, r, g, b;
if (!read_uchar(map, fsize, &position, &b)) goto close_file;
if (!read_uchar(map, fsize, &position, &g)) goto close_file;
if (!read_uchar(map, fsize, &position, &r)) goto close_file;
if (!read_uchar(map, fsize, &position, &a)) goto close_file;
a = 0xff;
pal[i] = ARGB_JOIN(a, r, g, b);
}
stride = ((w + 31) / 32);
maskbuf = alloca(stride * h);
pixbuf = alloca(stride * 32 * 4); // more than enough
if (bitcount == 1)
{
pstride = stride * 4;
for (i = 0; i < h; i++)
{
pix = surface + (i * ilp->w);
if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
p = pixbuf;
if (i >= (int)ilp->h) continue;
for (j = 0; j < w; j++)
{
if (j >= (int)ilp->w) break;
if ((j & 0x7) == 0x0)
{
*pix = pal[*p >> 7];
}
else if ((j & 0x7) == 0x1)
{
*pix = pal[(*p >> 6) & 0x1];
}
else if ((j & 0x7) == 0x2)
{
*pix = pal[(*p >> 5) & 0x1];
}
else if ((j & 0x7) == 0x3)
{
*pix = pal[(*p >> 4) & 0x1];
}
else if ((j & 0x7) == 0x4)
{
*pix = pal[(*p >> 3) & 0x1];
}
else if ((j & 0x7) == 0x5)
{
*pix = pal[(*p >> 2) & 0x1];
}
else if ((j & 0x7) == 0x6)
{
*pix = pal[(*p >> 1) & 0x1];
}
else
{
*pix = pal[*p & 0x1];
p++;
}
pix++;
}
}
}
else if (bitcount == 4)
{
pstride = ((w + 7) / 8) * 4;
for (i = 0; i < h; i++)
{
pix = surface + (i * ilp->w);
if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
p = pixbuf;
if (i >= (int)ilp->h) continue;
for (j = 0; j < w; j++)
{
if (j >= (int)ilp->w) break;
if ((j & 0x1) == 0x1)
{
*pix = pal[*p & 0x0f];
p++;
}
else
{
*pix = pal[*p >> 4];
}
pix++;
}
}
}
else if (bitcount == 8)
{
pstride = ((w + 3) / 4) * 4;
for (i = 0; i < h; i++)
{
pix = surface + (i * ilp->w);
if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
p = pixbuf;
if (i >= (int)ilp->h) continue;
for (j = 0; j < w; j++)
{
if (j >= (int)ilp->w) break;
*pix = pal[*p];
p++;
pix++;
}
}
}
else if (bitcount == 24)
{
pstride = w * 3;
for (i = 0; i < h; i++)
{
pix = surface + (i * ilp->w);
if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
p = pixbuf;
if (i >= (int)ilp->h) continue;
for (j = 0; j < w; j++)
{
unsigned char a, r, g, b;
if (j >= (int)ilp->w) break;
b = p[0];
g = p[1];
r = p[2];
p += 3;
a = 0xff;
*pix = ARGB_JOIN(a, r, g, b);
pix++;
}
}
}
else if (bitcount == 32)
{
pstride = w * 4;
for (i = 0; i < h; i++)
{
pix = surface + (i * ilp->w);
if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
p = pixbuf;
if (i >= (int)ilp->h) continue;
for (j = 0; j < w; j++)
{
unsigned char a, r, g, b;
if (j >= (int)ilp->w) break;
b = p[0];
g = p[1];
r = p[2];
a = p[3];
p += 4;
if (a) none_zero_alpha = 1;
*pix = ARGB_JOIN(a, r, g, b);
pix++;
}
}
}
if (!none_zero_alpha)
{
if (!read_mem(map, fsize, &position, maskbuf, stride * 4 * h)) goto close_file;
// apply mask
pix = surface;
for (i = 0; i < h; i++)
{
unsigned char *m;
pix = surface + (i * ilp->w);
if (!right_way_up) pix = surface + ((ilp->h - 1 - i) * ilp->w);
m = maskbuf + (stride * i * 4);
if (i >= (int)ilp->h) continue;
for (j = 0; j < w; j++)
{
if (j >= (int)ilp->w) break;
if (*m & (1 << (7 - (j & 0x7))))
A_VAL(pix) = 0x00;
else
A_VAL(pix) = 0xff;
if ((j & 0x7) == 0x7) m++;
pix++;
}
}
}
eina_file_map_free(f, map);
eina_file_close(f);
evas_cserve2_image_premul(ilp);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
close_file:
if (map) eina_file_map_free(f, map);
eina_file_close(f);
return EINA_FALSE;
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"ico",
evas_image_load_file_head_ico,
evas_image_load_file_data_ico
};
static Eina_Bool
module_init(void)
{
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -0,0 +1,573 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include <ctype.h>
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
#define FILE_BUFFER_SIZE 1024 * 32
#define FILE_BUFFER_UNREAD_SIZE 16
/* The buffer to load pmaps images */
typedef struct Pmaps_Buffer Pmaps_Buffer;
struct Pmaps_Buffer
{
Eina_File *file;
void *map;
size_t position;
/* the buffer */
DATA8 buffer[FILE_BUFFER_SIZE];
DATA8 unread[FILE_BUFFER_UNREAD_SIZE];
DATA8 *current;
DATA8 *end;
char type[3];
unsigned char unread_len:7;
unsigned char last_buffer:1;
/* image properties */
int w;
int h;
int max;
/* interface */
int (*int_get) (Pmaps_Buffer *b, int *val);
int (*color_get) (Pmaps_Buffer *b, DATA32 *color);
};
/* internal used functions */
static Eina_Bool pmaps_buffer_open(Pmaps_Buffer *b, const char *filename, int *error);
static void pmaps_buffer_close(Pmaps_Buffer *b);
static Eina_Bool pmaps_buffer_header_parse(Pmaps_Buffer *b, int *error);
static int pmaps_buffer_plain_int_get(Pmaps_Buffer *b, int *val);
static int pmaps_buffer_1byte_int_get(Pmaps_Buffer *b, int *val);
static int pmaps_buffer_2byte_int_get(Pmaps_Buffer *b, int *val);
static int pmaps_buffer_gray_get(Pmaps_Buffer *b, DATA32 *color);
static int pmaps_buffer_rgb_get(Pmaps_Buffer *b, DATA32 *color);
static int pmaps_buffer_plain_bw_get(Pmaps_Buffer *b, DATA32 *color);
static size_t pmaps_buffer_plain_update(Pmaps_Buffer *b);
static size_t pmaps_buffer_raw_update(Pmaps_Buffer *b);
static int pmaps_buffer_comment_skip(Pmaps_Buffer *b);
static Eina_Bool
evas_image_load_file_head_pmaps(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
Pmaps_Buffer b;
if (!pmaps_buffer_open(&b, file, error))
{
pmaps_buffer_close(&b);
return EINA_FALSE;
}
if (!pmaps_buffer_header_parse(&b, error))
{
pmaps_buffer_close(&b);
return EINA_FALSE;
}
ilp->w = b.w;
ilp->h = b.h;
pmaps_buffer_close(&b);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
}
static Eina_Bool
evas_image_load_file_data_pmaps(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
Pmaps_Buffer b;
int pixels;
DATA32 *ptr;
if (!pmaps_buffer_open(&b, file, error))
{
pmaps_buffer_close(&b);
return EINA_FALSE;
}
if (!pmaps_buffer_header_parse(&b, error))
{
pmaps_buffer_close(&b);
return EINA_FALSE;
}
pixels = b.w * b.h;
ptr = ilp->buffer;
if (!ptr)
{
pmaps_buffer_close(&b);
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return EINA_FALSE;
}
if (b.type[1] != '4')
{
while (pixels > 0 && b.color_get(&b, ptr))
{
pixels--;
ptr++;
}
}
else
{
while (pixels > 0
&& (b.current != b.end || pmaps_buffer_raw_update(&b)))
{
int i;
for (i = 7; i >= 0 && pixels > 0; i--)
{
if (*b.current & (1 << i))
*ptr = 0xff000000;
else
*ptr = 0xffffffff;
ptr++;
pixels--;
}
b.current++;
}
}
/* if there are some pix missing, give them a proper default */
memset(ptr, 0xff, 4 * pixels);
pmaps_buffer_close(&b);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
}
/* internal used functions */
static Eina_Bool
pmaps_buffer_open(Pmaps_Buffer *b, const char *filename, int *error)
{
size_t len;
b->file = eina_file_open(filename, EINA_FALSE);
if (!b->file)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
b->map = eina_file_map_all(b->file, EINA_FILE_SEQUENTIAL);
if (!b->map)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
eina_file_close(b->file);
b->file = NULL;
return EINA_FALSE;
}
b->position = 0;
*b->buffer = 0;
*b->unread = 0;
b->last_buffer = 0;
b->unread_len = 0;
len = pmaps_buffer_plain_update(b);
if (len < 3)
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
eina_file_map_free(b->file, b->map);
eina_file_close(b->file);
b->map = NULL;
b->file = NULL;
return EINA_FALSE;
}
/* copy the type */
b->type[0] = b->buffer[0];
b->type[1] = b->buffer[1];
b->type[2] = 0;
/* skip the PX */
b->current = b->buffer + 2;
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
}
static void
pmaps_buffer_close(Pmaps_Buffer *b)
{
if (b->file)
{
if (b->map) eina_file_map_free(b->file, b->map);
b->map = NULL;
eina_file_close(b->file);
b->file = NULL;
}
}
static Eina_Bool
pmaps_buffer_header_parse(Pmaps_Buffer *b, int *error)
{
/* if there is no P at the beginning it is not a file we can parse */
if (b->type[0] != 'P')
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
/* get the width */
if (!pmaps_buffer_plain_int_get(b, &(b->w)) || b->w < 1)
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
/* get the height */
if (!pmaps_buffer_plain_int_get(b, &(b->h)) || b->h < 1)
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
/* get the maximum value. P1 and P4 don't have a maximum value. */
if (!(b->type[1] == '1' || b->type[1] == '4')
&& (!pmaps_buffer_plain_int_get(b, &(b->max)) || b->max < 1))
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
/* set up the color get callback */
switch (b->type[1])
{
/* Black and White */
case '1':
b->color_get = pmaps_buffer_plain_bw_get;
break;
case '4':
/* Binary black and white use another format */
b->color_get = NULL;
break;
case '2':
case '5':
b->color_get = pmaps_buffer_gray_get;
break;
case '3':
case '6':
b->color_get = pmaps_buffer_rgb_get;
break;
case '7':
/* XXX write me */
return 0;
break;
default:
return 0;
}
/* set up the int get callback */
switch (b->type[1])
{
/* RAW */
case '5':
case '6':
if (b->max < 256)
b->int_get = pmaps_buffer_1byte_int_get;
else
b->int_get = pmaps_buffer_2byte_int_get;
if (b->current == b->end && !pmaps_buffer_raw_update(b))
return 0;
b->current++;
break;
/* Plain */
case '2':
case '3':
b->int_get = pmaps_buffer_plain_int_get;
break;
/* Black and White Bitmaps don't use that callback */
case '1':
case '4':
b->int_get = NULL;
/* we need to skip the next character fpr P4 it
* doesn't hurt if we do it for the P1 as well */
b->current++;
break;
}
return 1;
}
static size_t
pmaps_buffer_plain_update(Pmaps_Buffer *b)
{
size_t r;
size_t max;
/* if we already are in the last buffer we can not update it */
if (b->last_buffer)
return 0;
/* if we have unread bytes we need to put them before the new read
* stuff */
if (b->unread_len)
memcpy(b->buffer, b->unread, b->unread_len);
max = FILE_BUFFER_SIZE - b->unread_len - 1;
if (b->position + max > eina_file_size_get(b->file))
max = eina_file_size_get(b->file) - b->position;
memcpy(&b->buffer[b->unread_len], b->map + b->position, max);
b->position += max;
r = max + b->unread_len;
/* we haven't read anything nor have we bytes in the unread buffer */
if (r == 0)
{
b->buffer[0] = '\0';
b->end = b->buffer;
b->last_buffer = 1;
return 0;
}
if (r < FILE_BUFFER_SIZE - 1)
{
/*we reached eof */ ;
b->last_buffer = 1;
}
b->buffer[r] = 0;
b->unread[0] = '\0';
b->unread_len = 0;
b->buffer[r] = '\0';
b->current = b->buffer;
b->end = b->buffer + r;
return r;
}
static size_t
pmaps_buffer_raw_update(Pmaps_Buffer *b)
{
size_t r;
size_t max;
if (b->last_buffer)
return 0;
if (b->unread_len)
memcpy(b->buffer, b->unread, b->unread_len);
max = FILE_BUFFER_SIZE - b->unread_len;
if (b->position + max > eina_file_size_get(b->file))
max = eina_file_size_get(b->file) - b->position;
memcpy(&b->buffer[b->unread_len], b->map + b->position, max);
b->position += max;
r = max + b->unread_len;
if (r < FILE_BUFFER_SIZE)
{
/*we reached eof */
b->last_buffer = 1;
}
b->end = b->buffer + r;
b->current = b->buffer;
if (b->unread_len)
{
/* the buffer is now read */
*b->unread = 0;
b->unread_len = 0;
}
return r;
}
static int
pmaps_buffer_plain_int_get(Pmaps_Buffer *b, int *val)
{
char *start;
DATA8 lastc;
/* first skip all white space
* Note: we are skipping here actually every character than is not
* a digit */
while (!isdigit(*b->current))
{
if (*b->current == '\0')
{
if (!pmaps_buffer_plain_update(b))
return 0;
continue;
}
if (*b->current == '#' && !pmaps_buffer_comment_skip(b))
return 0;
b->current++;
}
start = (char *)b->current;
/* now find the end of the number */
while (isdigit(*b->current))
b->current++;
lastc = *b->current;
*b->current = '\0';
*val = atoi(start);
*b->current = lastc;
return 1;
}
static int
pmaps_buffer_1byte_int_get(Pmaps_Buffer *b, int *val)
{
/* are we at the end of the buffer? */
if (b->current == b->end && !pmaps_buffer_raw_update(b))
return 0;
*val = *b->current;
b->current++;
return 1;
}
static int
pmaps_buffer_2byte_int_get(Pmaps_Buffer *b, int *val)
{
/* are we at the end of the buffer? */
if (b->current == b->end && !pmaps_buffer_raw_update(b))
return 0;
*val = (int)(*b->current << 8);
b->current++;
/* are we at the end of the buffer? */
if (b->current == b->end && !pmaps_buffer_raw_update(b))
return 0;
*val |= *b->current;
b->current++;
return 1;
}
static int
pmaps_buffer_comment_skip(Pmaps_Buffer *b)
{
while (*b->current != '\n')
{
if (*b->current == '\0')
{
if (!pmaps_buffer_plain_update(b))
return 0;
continue;
}
b->current++;
}
return 1;
}
static int
pmaps_buffer_rgb_get(Pmaps_Buffer *b, DATA32 *color)
{
int vr, vg, vb;
if (!b->int_get(b, &vr) || !b->int_get(b, &vg) || !b->int_get(b, &vb))
return 0;
if (b->max != 255)
{
vr = (vr * 255) / b->max;
vg = (vg * 255) / b->max;
vb = (vb * 255) / b->max;
}
if (vr > 255)
vr = 255;
if (vg > 255)
vg = 255;
if (vb > 255)
vb = 255;
*color = ARGB_JOIN(0xff, vr, vg, vb);
return 1;
}
static int
pmaps_buffer_gray_get(Pmaps_Buffer *b, DATA32 *color)
{
int val;
if (!b->int_get(b, &val))
return 0;
if (b->max != 255)
val = (val * 255) / b->max;
if (val > 255)
val = 255;
*color = ARGB_JOIN(0xff, val, val, val);
return 1;
}
static int
pmaps_buffer_plain_bw_get(Pmaps_Buffer *b, DATA32 *val)
{
/* first skip all white space
* Note: we are skipping here actually every character than is not
* a digit */
while (!isdigit(*b->current))
{
if (*b->current == '\0')
{
if (!pmaps_buffer_raw_update(b))
return 0;
continue;
}
if (*b->current == '#' && !pmaps_buffer_comment_skip(b))
return 0;
b->current++;
}
if (*b->current == '0')
*val = 0xffffffff;
else
*val = 0xff000000;
b->current++;
return 1;
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"pmaps",
evas_image_load_file_head_pmaps,
evas_image_load_file_data_pmaps
};
static Eina_Bool
module_init(void)
{
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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

View File

@ -0,0 +1,310 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <png.h>
#include <setjmp.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#ifdef _WIN32_WCE
# define E_FOPEN(file, mode) evil_fopen_native((file), (mode))
# define E_FREAD(buffer, size, count, stream) evil_fread_native(buffer, size, count, stream)
# define E_FCLOSE(stream) evil_fclose_native(stream)
#else
# define E_FOPEN(file, mode) fopen((file), (mode))
# define E_FREAD(buffer, size, count, stream) fread(buffer, size, count, stream)
# define E_FCLOSE(stream) fclose(stream)
#endif
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
#define PNG_BYTES_TO_CHECK 4
static Eina_Bool
evas_image_load_file_head_png(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
png_uint_32 w32, h32;
FILE *f;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
int bit_depth, color_type, interlace_type;
unsigned char buf[PNG_BYTES_TO_CHECK];
char hasa;
hasa = 0;
f = E_FOPEN(file, "rb");
if (!f)
{
*error = CSERVE2_DOES_NOT_EXIST;
return EINA_FALSE;
}
/* if we havent read the header before, set the header data */
if (E_FREAD(buf, PNG_BYTES_TO_CHECK, 1, f) != 1)
{
*error = CSERVE2_UNKNOWN_FORMAT;
goto close_file;
}
if (png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK))
{
*error = CSERVE2_UNKNOWN_FORMAT;
goto close_file;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
*error = CSERVE2_CORRUPT_FILE;
goto close_file;
}
png_init_io(png_ptr, f);
png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
(png_uint_32 *) (&h32), &bit_depth, &color_type,
&interlace_type, NULL, NULL);
if ((w32 < 1) || (h32 < 1) || (w32 > IMG_MAX_SIZE) || (h32 > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w32, h32))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
if (IMG_TOO_BIG(w32, h32))
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
else
*error = CSERVE2_GENERIC;
goto close_file;
}
if (ilp->opts.scale_down_by > 1)
{
ilp->w = (int) w32 / ilp->opts.scale_down_by;
ilp->h = (int) h32 / ilp->opts.scale_down_by;
if ((ilp->w < 1) || (ilp->h < 1))
{
*error = CSERVE2_GENERIC;
goto close_file;
}
}
else
{
ilp->w = (int) w32;
ilp->h = (int) h32;
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1;
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
if (hasa) ilp->alpha = 1;
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
E_FCLOSE(f);
*error = CSERVE2_NONE;
return EINA_TRUE;
close_file:
E_FCLOSE(f);
return EINA_FALSE;
}
static Eina_Bool
evas_image_load_file_data_png(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
unsigned char *surface;
png_uint_32 w32, h32;
int w, h;
FILE *f;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
int bit_depth, color_type, interlace_type;
unsigned char buf[PNG_BYTES_TO_CHECK];
unsigned char **lines;
char hasa;
int i, j;
int scale_ratio = 1, image_w = 0;
unsigned char *tmp_line;
DATA32 *src_ptr, *dst_ptr;
hasa = 0;
f = E_FOPEN(file, "rb");
if (!f)
{
*error = CSERVE2_DOES_NOT_EXIST;
return EINA_FALSE;
}
/* if we havent read the header before, set the header data */
if (E_FREAD(buf, PNG_BYTES_TO_CHECK, 1, f) != 1)
{
*error = CSERVE2_CORRUPT_FILE;
goto close_file;
}
if (png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK))
{
*error = CSERVE2_CORRUPT_FILE;
goto close_file;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
*error = CSERVE2_CORRUPT_FILE;
goto close_file;
}
png_init_io(png_ptr, f);
png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
(png_uint_32 *) (&h32), &bit_depth, &color_type,
&interlace_type, NULL, NULL);
image_w = w32;
if (ilp->opts.scale_down_by > 1)
{
scale_ratio = ilp->opts.scale_down_by;
w32 /= scale_ratio;
h32 /= scale_ratio;
}
surface = (unsigned char *) ilp->buffer;
if (!surface)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
*error = CSERVE2_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
if ((w32 != ilp->w) || (h32 != ilp->h))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
*error = CSERVE2_GENERIC;
goto close_file;
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1;
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
if (hasa) ilp->alpha = 1;
/* Prep for transformations... ultimately we want ARGB */
/* expand palette -> RGB if necessary */
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
/* expand gray (w/reduced bits) -> 8-bit RGB if necessary */
if ((color_type == PNG_COLOR_TYPE_GRAY) ||
(color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
{
png_set_gray_to_rgb(png_ptr);
if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
}
/* expand transparency entry -> alpha channel if present */
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
/* reduce 16bit color -> 8bit color if necessary */
if (bit_depth > 8) png_set_strip_16(png_ptr);
/* pack all pixels to byte boundaries */
png_set_packing(png_ptr);
w = ilp->w;
h = ilp->h;
/* we want ARGB */
#ifdef WORDS_BIGENDIAN
png_set_swap_alpha(png_ptr);
if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
#else
png_set_bgr(png_ptr);
if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
#endif
/* we read image line by line if scale down was set */
if (scale_ratio == 1)
{
lines = (unsigned char **) alloca(h * sizeof(unsigned char *));
for (i = 0; i < h; i++)
lines[i] = surface + (i * w * sizeof(DATA32));
png_read_image(png_ptr, lines);
png_read_end(png_ptr, info_ptr);
}
else
{
tmp_line = (unsigned char *) alloca(image_w * sizeof(DATA32));
dst_ptr = (DATA32 *)surface;
for (i = 0; i < h; i++)
{
png_read_row(png_ptr, tmp_line, NULL);
src_ptr = (DATA32 *)tmp_line;
for (j = 0; j < w; j++)
{
*dst_ptr = *src_ptr;
dst_ptr++;
src_ptr += scale_ratio;
}
for (j = 0; j < (scale_ratio - 1); j++)
{
png_read_row(png_ptr, tmp_line, NULL);
}
}
}
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
E_FCLOSE(f);
evas_cserve2_image_premul(ilp);
*error = CSERVE2_NONE;
return EINA_TRUE;
close_file:
E_FCLOSE(f);
return EINA_FALSE;
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"png",
evas_image_load_file_head_png,
evas_image_load_file_data_png
};
static Eina_Bool
module_init(void)
{
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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

View File

@ -0,0 +1,981 @@
#define _XOPEN_SOURCE
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
typedef struct _PSD_Header PSD_Header;
typedef enum _PSD_Mode
{
PSD_GREYSCALE = 1,
PSD_INDEXED = 2,
PSD_RGB = 3,
PSD_CMYK = 4
} PSD_Mode;
struct _PSD_Header
{
unsigned char signature[4];
unsigned short version;
unsigned char reserved[9];
unsigned short channels;
unsigned int height;
unsigned int width;
unsigned short depth;
unsigned short channel_num;
PSD_Mode mode;
};
enum {
READ_COMPRESSED_SUCCESS,
READ_COMPRESSED_ERROR_FILE_CORRUPT,
READ_COMPRESSED_ERROR_FILE_READ_ERROR
};
static Eina_Bool get_compressed_channels_length(PSD_Header *Head,
const unsigned char *map, size_t length, size_t *position,
unsigned short *rle_table,
unsigned int *chanlen);
static int
read_ushort(const unsigned char *map, size_t length, size_t *position, unsigned short *ret)
{
if (*position + 2 > length) return 0;
// FIXME: need to check order
*ret = (map[(*position) + 0] << 8) | map[(*position) + 1];
*position += 2;
return 1;
}
static int
read_uint(const unsigned char *map, size_t length, size_t *position, unsigned int *ret)
{
if (*position + 4 > length) return 0;
// FIXME: need to check order
*ret = ARGB_JOIN(map[(*position) + 0], map[(*position) + 1], map[(*position) + 2], map[(*position) + 3]);
*position += 4;
return 1;
}
static int
read_block(const unsigned char *map, size_t length, size_t *position, void *target, size_t size)
{
if (*position + size > length) return 0;
memcpy(target, map + *position, size);
*position += size;
return 1;
}
// Internal function used to get the Psd header from the current file.
Eina_Bool
psd_get_header(PSD_Header *header, const unsigned char *map, size_t length, size_t *position)
{
unsigned short tmp;
#define CHECK_RET(Call) \
if (!Call) return EINA_FALSE;
CHECK_RET(read_block(map, length, position, header->signature, 4));
CHECK_RET(read_ushort(map, length, position, &header->version));
CHECK_RET(read_block(map, length, position, header->reserved, 6));
CHECK_RET(read_ushort(map, length, position, &header->channels));
CHECK_RET(read_uint(map, length, position, &header->height));
CHECK_RET(read_uint(map, length, position, &header->width));
CHECK_RET(read_ushort(map, length, position, &header->depth));
CHECK_RET(read_ushort(map, length, position, &tmp));
header->mode = tmp;
#undef CHECK_RET
/* fprintf(stderr, "<<<<<<<<<<<\nsignature : %c%c%c%c\n", */
/* header->signature[0], */
/* header->signature[1], */
/* header->signature[2], */
/* header->signature[3]); */
/* fprintf(stderr, "version : %i\n", header->version); */
/* fprintf(stderr, "channels : %i\n", header->channels); */
/* fprintf(stderr, "width x height : %dx%d\n", header->width, header->height); */
/* fprintf(stderr, "depth : %i\n", header->depth); */
/* fprintf(stderr, "mode : %i\n>>>>>>>>>>>>\n", header->mode); */
return EINA_TRUE;
}
// Internal function used to check if the HEADER is a valid Psd header.
Eina_Bool
is_psd(PSD_Header *header)
{
if (strncmp((char*)header->signature, "8BPS", 4))
return EINA_FALSE;
if (header->version != 1)
return EINA_FALSE;
if (header->channels < 1 || header->channels > 24)
return EINA_FALSE;
if (header->height < 1 || header->width < 1)
return EINA_FALSE;
if (header->depth != 1 && header->depth != 8 && header->depth != 16)
return EINA_FALSE;
return EINA_TRUE;
}
static Eina_Bool
evas_image_load_file_head_psd(Evas_Img_Load_Params *ilp, const char *FileName,
const char *key __UNUSED__, int *error)
{
Eina_File *f;
void *map;
size_t length;
size_t position;
PSD_Header header;
Eina_Bool correct;
*error = EVAS_LOAD_ERROR_NONE;
f = eina_file_open(FileName, 0);
if (f == NULL)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
length = eina_file_size_get(f);
position = 0;
if (!map || length < 1)
{
eina_file_close(f);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
correct = psd_get_header(&header, map, length, &position);
eina_file_map_free(f, map);
eina_file_close(f);
if (!correct || !is_psd(&header))
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
ilp->w = header.width;
ilp->h = header.height;
if (header.channels == 3) ilp->alpha = 0;
else ilp->alpha = 1;
return EINA_TRUE;
}
static unsigned int
read_compressed_channel(const unsigned char *map, size_t length, size_t *position,
const unsigned int channel_length __UNUSED__,
unsigned int size,
unsigned char* channel)
{
// FIXME: what does channel_length means, and why is it not used
unsigned int i;
char headbyte, c;
#define CHECK_RET(Call) \
if (!Call) return READ_COMPRESSED_ERROR_FILE_READ_ERROR; \
for (i = 0; i < size; )
{
CHECK_RET(read_block(map, length, position, &headbyte, 1));
if (headbyte >= 0)
{
if (i + headbyte > size)
return READ_COMPRESSED_ERROR_FILE_CORRUPT;
CHECK_RET(read_block(map, length, position, channel + i, headbyte + 1));
i += headbyte + 1;
}
else if (headbyte >= -127 && headbyte <= -1)
{
int run;
CHECK_RET(read_block(map, length, position, &c, 1));
run = c;
/* if (run == -1) */
/* return READ_COMPRESSED_ERROR_FILE_READ_ERROR; */
if (i + (-headbyte + 1) > size)
return READ_COMPRESSED_ERROR_FILE_CORRUPT;
memset(channel + i, run, -headbyte + 1);
i += -headbyte + 1;
}
}
#undef CHECK_RET
return READ_COMPRESSED_SUCCESS;
}
static Eina_Bool
psd_get_data(PSD_Header *head,
const unsigned char *map, size_t length, size_t *position,
unsigned char *buffer, Eina_Bool compressed,
int *error)
{
unsigned int c, x, y, numchan, bps, bpc, bpp;
unsigned int pixels_count;
unsigned char *channel = NULL;
unsigned char *data = NULL;
// Added 01-07-2009: This is needed to correctly load greyscale and
// paletted images.
switch (head->mode)
{
case PSD_GREYSCALE:
case PSD_INDEXED:
numchan = 1;
break;
default:
numchan = 3;
}
bpp = head->channels;
bpc = head->depth / 8;
pixels_count = head->width * head->height;
data = malloc(sizeof (unsigned char) * pixels_count * bpp);
if (!data) return EINA_FALSE;
channel = malloc(sizeof (unsigned char) * pixels_count * bpc);
if (!channel)
{
free(data);
return EINA_FALSE;
}
bps = head->width * head->channels * bpc;
// @TODO: Add support for this in, though I have yet to run across a .psd
// file that uses this.
if (compressed && bpc == 2)
{
free(data);
free(channel);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
#define CHECK_RET(Call) \
if (!Call) \
{ \
free(data); \
free(channel); \
return EINA_FALSE; \
}
if (!compressed)
{
if (bpc == 1)
{
for (c = 0; c < numchan; c++)
{
unsigned char *tmp = channel;
CHECK_RET(read_block(map, length, position, tmp, pixels_count));
for (y = 0; y < head->height * bps; y += bps)
{
for (x = 0; x < bps; x += bpp, tmp++)
{
data[y + x + c] = *tmp;
}
}
}
// Accumulate any remaining channels into a single alpha channel
//@TODO: This needs to be changed for greyscale images.
for (; c < head->channels; c++)
{
unsigned char *tmp = channel;
CHECK_RET(read_block(map, length, position, channel, pixels_count));
for (y = 0; y < head->height * bps; y += bps)
{
for (x = 0; x < bps; x += bpp, tmp++)
{
unsigned short newval;
// previous formula was : (old / 255 * new / 255) * 255
newval = (*tmp) * data[y + x + 3];
data[y + x + 3] = newval >> 8;
}
}
}
}
else
{
int bps2;
bps2 = bps / 2;
// iCurImage->Bpc == 2
for (c = 0; c < numchan; c++)
{
unsigned short *shortptr = (unsigned short*) channel;
CHECK_RET(read_block(map, length, position, channel, pixels_count * 2));
for (y = 0; y < head->height * bps2; y += bps2)
{
for (x = 0; x < (unsigned int)bps2; x += bpp, shortptr++)
{
((unsigned short*)data)[y + x + c] = *shortptr;
}
}
}
// Accumulate any remaining channels into a single alpha channel
//@TODO: This needs to be changed for greyscale images.
for (; c < head->channels; c++)
{
unsigned short *shortptr = (unsigned short*) channel;
CHECK_RET(read_block(map, length, position, channel, pixels_count * 2));
for (y = 0; y < head->height * bps2; y += bps2)
{
for (x = 0; x < (unsigned int)bps2; x += bpp, shortptr)
{
unsigned int newval;
newval = *shortptr * ((unsigned short*)data)[y + x + 3];
((unsigned short*)data)[y + x + 3] = newval >> 16;
}
}
}
}
}
else
{
unsigned short *rle_table;
unsigned int *chanlen;
rle_table = alloca(head->height * head->channel_num * sizeof (unsigned short));
chanlen = alloca(head->channel_num * sizeof (unsigned int));
if (!get_compressed_channels_length(head, map, length, position, rle_table, chanlen))
goto file_read_error;
for (c = 0; c < numchan; c++)
{
unsigned char *tmp = channel;
int err;
err = read_compressed_channel(map, length, position,
chanlen[c],
pixels_count,
channel);
if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
goto file_corrupt;
else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
goto file_read_error;
for (y = 0; y < head->height * bps; y += bps)
{
for (x = 0; x < bps; x += bpp, tmp++)
{
data[y + x + c] = *tmp;
}
}
}
// Initialize the alpha channel to solid
//@TODO: This needs to be changed for greyscale images.
if (head->channels >= 4)
{
for (y = 0; y < head->height * bps; y += bps)
{
for (x = 0; x < bps; x += bpp)
{
data[y + x + 3] = 255;
}
}
for (; c < head->channels; c++)
{
unsigned char *tmp = channel;
int err;
err = read_compressed_channel(map, length, position,
chanlen[c],
pixels_count,
channel);
if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
goto file_corrupt;
else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
goto file_read_error;
for (y = 0; y < head->height * bps; y += bps)
{
for (x = 0; x < bps; x += bpp, tmp++)
{
unsigned short newval;
newval = *tmp * data[y + x + 3];
data[y + x + 3] = newval >> 8;
}
}
}
}
}
if (bpp == 3)
{
for (x = 0; x < pixels_count; x++)
{
buffer[x * 4 + 0] = data[x * 3 + 2];
buffer[x * 4 + 1] = data[x * 3 + 1];
buffer[x * 4 + 2] = data[x * 3 + 0];
buffer[x * 4 + 3] = 255;
}
}
else
{
// BRGA to RGBA
for (x= 0; x < pixels_count; x++)
{
buffer[x * 4 + 0] = data[x * 4 + 2];
buffer[x * 4 + 1] = data[x * 4 + 1];
buffer[x * 4 + 2] = data[x * 4 + 0];
buffer[x * 4 + 3] = data[x * 4 + 3];
}
}
free(channel);
free(data);
return EINA_TRUE;
#undef CHECK_RET
file_corrupt:
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
file_read_error:
free(channel);
free(data);
return EINA_FALSE;
}
static Eina_Bool
get_single_channel(PSD_Header *head,
const unsigned char *map, size_t length, size_t *position,
unsigned char *buffer,
Eina_Bool compressed)
{
unsigned int i, bpc;
char headbyte;
int c;
int pixels_count;
bpc = (head->depth / 8);
pixels_count = head->width * head->height;
#define CHECK_RET(Call) \
if (!Call) return EINA_FALSE;
if (!compressed)
{
if (bpc == 1)
{
CHECK_RET(read_block(map, length, position, buffer, pixels_count));
}
else
{ // Bpc == 2
CHECK_RET(read_block(map, length, position, buffer, pixels_count * 2));
}
}
else
{
for (i = 0; i < (unsigned int)pixels_count; )
{
CHECK_RET(read_block(map, length, position, &headbyte, 1));
if (headbyte >= 0)
{ // && HeadByte <= 127
CHECK_RET(read_block(map, length, position, buffer + i, headbyte + 1));
i += headbyte + 1;
}
if (headbyte >= -127 && headbyte <= -1)
{
int run;
CHECK_RET(read_block(map, length, position, &c, 1));
run = c;
if (run == -1) return EINA_FALSE;
memset(buffer + i, run, -headbyte + 1);
i += -headbyte + 1;
}
}
}
#undef CHECK_RET
return EINA_TRUE;
}
static Eina_Bool
read_psd_grey(Evas_Img_Load_Params *ilp, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
{
unsigned int color_mode, resource_size, misc_info;
unsigned short compressed;
void *surface = NULL;
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
#define CHECK_RET(Call) \
if (!Call) return EINA_FALSE;
CHECK_RET(read_uint(map, length, position, &color_mode));
// Skip over the 'color mode data section'
*position += color_mode;
CHECK_RET(read_uint(map, length, position, &resource_size));
// Read the 'image resources section'
*position += resource_size;
CHECK_RET(read_uint(map, length, position, &misc_info));
*position += misc_info;
CHECK_RET(read_ushort(map, length, position, &compressed));
ilp->w = head->width;
ilp->h = head->height;
if (head->channels == 3) ilp->alpha = 0;
else ilp->alpha = 1;
head->channel_num = head->channels;
// Temporary to read only one channel...some greyscale .psd files have 2.
head->channels = 1;
switch (head->depth)
{
case 8:
case 16:
break;
default:
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
surface = ilp->buffer;
if (!surface)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto cleanup_error;
}
if (!psd_get_data(head, map, length, position, surface, compressed, error))
goto cleanup_error;
return EINA_TRUE;
#undef CHECK_RET
cleanup_error:
return EINA_FALSE;
}
Eina_Bool
read_psd_indexed(Evas_Img_Load_Params *ilp, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
{
unsigned int color_mode, resource_size, misc_info;
unsigned short compressed;
void *surface;
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
#define CHECK_RET(Call) \
if (!(Call)) return EINA_FALSE;
CHECK_RET(read_uint(map, length, position, &color_mode));
CHECK_RET(!(color_mode % 3));
/*
Palette = (unsigned char*)malloc(Colormode);
if (Palette == NULL)
return EINA_FALSE;
if (fread(&Palette, 1, Colormode, file) != Colormode)
goto cleanup_error;
*/
// Skip over the 'color mode data section'
*position += color_mode;
// Read the 'image resources section'
CHECK_RET(read_uint(map, length, position, &resource_size));
*position += resource_size;
CHECK_RET(read_uint(map, length, position, &misc_info));
*position += misc_info;
CHECK_RET(read_ushort(map, length, position, &compressed));
if (head->channels != 1 || head->depth != 8)
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
head->channel_num = head->channels;
ilp->w = head->width;
ilp->h = head->height;
if (head->channels == 3) ilp->alpha = 0;
else ilp->alpha = 1;
surface = ilp->buffer;
if (!surface)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return EINA_FALSE;
}
if (!psd_get_data(head, map, length, position, surface, compressed, error))
return EINA_FALSE;
return EINA_TRUE;
#undef CHECK_RET
}
Eina_Bool
read_psd_rgb(Evas_Img_Load_Params *ilp, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
{
unsigned int color_mode, resource_size, misc_info;
unsigned short compressed;
void *surface;
#define CHECK_RET(Call) \
if (!Call) return EINA_FALSE;
CHECK_RET(read_uint(map, length, position, &color_mode));
// Skip over the 'color mode data section'
*position += color_mode;
// Read the 'image resources section'
CHECK_RET(read_uint(map, length, position, &resource_size));
*position += resource_size;
CHECK_RET(read_uint(map, length, position, &misc_info));
*position += misc_info;
CHECK_RET(read_ushort(map, length, position, &compressed));
head->channel_num = head->channels;
switch (head->depth)
{
case 8:
case 16:
break;
default:
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
ilp->w = head->width;
ilp->h = head->height;
if (head->channels == 3) ilp->alpha = 0;
else ilp->alpha = 1;
surface = ilp->buffer;
if (!surface)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto cleanup_error;
}
if (!psd_get_data(head, map, length, position, surface, compressed, error))
goto cleanup_error;
evas_cserve2_image_premul(ilp);
return EINA_TRUE;
#undef CHECK_RET
cleanup_error:
return EINA_FALSE;
}
Eina_Bool
read_psd_cmyk(Evas_Img_Load_Params *ilp, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
{
unsigned int color_mode, resource_size, misc_info, size, j, data_size;
unsigned short compressed;
unsigned int format, type;
unsigned char *kchannel = NULL;
void *surface;
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
#define CHECK_RET(Call) \
if (!Call) return EINA_FALSE;
CHECK_RET(read_uint(map, length, position, &color_mode));
// Skip over the 'color mode data section'
*position += color_mode;
CHECK_RET(read_uint(map, length, position, &resource_size));
// Read the 'image resources section'
*position += resource_size;
CHECK_RET(read_uint(map, length, position, &misc_info));
*position += misc_info;
CHECK_RET(read_ushort(map, length, position, &compressed));
switch (head->channels)
{
case 4:
format = 0x1907;
head->channel_num = 4;
head->channels = 3;
break;
case 5:
format = 0x1908;
head->channel_num = 5;
head->channels = 4;
break;
default:
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
switch (head->depth)
{
case 8:
type = 1;
break;
case 16:
type = 2;
break;
default:
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
ilp->w = head->width;
ilp->h = head->height;
if (head->channels == 3) ilp->alpha = 0;
else ilp->alpha = 1;
surface = ilp->buffer;
if (!surface)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto cleanup_error;
}
if (!psd_get_data(head, map, length, position, surface, compressed, error))
goto cleanup_error;
size = type * ilp->w * ilp->h;
kchannel = malloc(size);
if (kchannel == NULL)
goto cleanup_error;
if (!get_single_channel(head, map, length, position, kchannel, compressed))
goto cleanup_error;
data_size = head->channels * type * ilp->w * ilp->h;
if (format == 0x1907)
{
unsigned char *tmp = surface;
const unsigned char *limit = tmp + data_size;
for (j = 0; tmp < limit; tmp++, j++)
{
int k;
for (k = 0; k < 3; k++)
*tmp = (*tmp * kchannel[j]) >> 8;
// FIXME: tmp[i+3] = 255;
}
}
else
{ // RGBA
unsigned char *tmp = surface;
const unsigned char *limit = tmp + data_size;
// The KChannel array really holds the alpha channel on this one.
for (j = 0; tmp < limit; tmp += 4, j++)
{
tmp[0] = (tmp[0] * tmp[3]) >> 8;
tmp[1] = (tmp[1] * tmp[3]) >> 8;
tmp[2] = (tmp[2] * tmp[3]) >> 8;
tmp[3] = kchannel[j]; // Swap 'K' with alpha channel.
}
}
free(kchannel);
evas_cserve2_image_premul(ilp);
return EINA_TRUE;
cleanup_error:
free(kchannel);
return EINA_FALSE;
}
static Eina_Bool
evas_image_load_file_data_psd(Evas_Img_Load_Params *ilp,
const char *file,
const char *key __UNUSED__,
int *error)
{
Eina_File *f;
void *map;
size_t length;
size_t position;
PSD_Header header;
Eina_Bool bpsd = EINA_FALSE;
f = eina_file_open(file, 0);
if (f == NULL)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return bpsd;
}
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
length = eina_file_size_get(f);
position = 0;
if (!map || length < 1)
{
eina_file_close(f);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
if (!psd_get_header(&header, map, length, &position) || !is_psd(&header))
{
eina_file_map_free(f, map);
eina_file_close(f);
*error = EVAS_LOAD_ERROR_GENERIC;
return EINA_FALSE;
}
ilp->w = header.width;
ilp->h = header.height;
*error = EVAS_LOAD_ERROR_NONE;
switch (header.mode)
{
case PSD_GREYSCALE: // Greyscale
bpsd = read_psd_grey(ilp, &header, map, length, &position, error);
break;
case PSD_INDEXED: // Indexed
bpsd = read_psd_indexed(ilp, &header, map, length, &position, error);
break;
case PSD_RGB: // RGB
bpsd = read_psd_rgb(ilp, &header, map, length, &position, error);
break;
case PSD_CMYK: // CMYK
bpsd = read_psd_cmyk(ilp, &header, map, length, &position, error);
break;
default :
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
bpsd = EINA_FALSE;
}
eina_file_map_free(f, map);
eina_file_close(f);
return bpsd;
}
static Eina_Bool
get_compressed_channels_length(PSD_Header *head,
const unsigned char *map, size_t length, size_t *position,
unsigned short *rle_table,
unsigned int *chanlen)
{
unsigned int j;
unsigned int c;
if (!read_block(map, length, position, rle_table,
sizeof (unsigned short) * head->height * head->channel_num))
return EINA_FALSE;
memset(chanlen, 0, head->channel_num * sizeof(unsigned int));
for (c = 0; c < head->channel_num; c++)
{
unsigned int i;
j = c * head->height;
for (i = 0; i < head->height; i++)
{
chanlen[c] += rle_table[i + j];
}
}
return EINA_TRUE;
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"psd",
evas_image_load_file_head_psd,
evas_image_load_file_data_psd
};
static Eina_Bool
module_init(void)
{
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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

View File

@ -0,0 +1,574 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
/* TGA pixel formats */
#define TGA_TYPE_MAPPED 1 // handle
#define TGA_TYPE_COLOR 2
#define TGA_TYPE_GRAY 3
#define TGA_TYPE_MAPPED_RLE 9 // handle
#define TGA_TYPE_COLOR_RLE 10
#define TGA_TYPE_GRAY_RLE 11
/* TGA header flags */
#define TGA_DESC_ABITS 0x0f
#define TGA_DESC_HORIZONTAL 0x10
#define TGA_DESC_VERTICAL 0x20
#define TGA_SIGNATURE "TRUEVISION-XFILE"
typedef struct _tga_header tga_header;
typedef struct _tga_footer tga_footer;
struct _tga_header
{
unsigned char idLength;
unsigned char colorMapType;
unsigned char imageType;
unsigned char colorMapIndexLo, colorMapIndexHi;
unsigned char colorMapLengthLo, colorMapLengthHi;
unsigned char colorMapSize;
unsigned char xOriginLo, xOriginHi;
unsigned char yOriginLo, yOriginHi;
unsigned char widthLo, widthHi;
unsigned char heightLo, heightHi;
unsigned char bpp;
unsigned char descriptor;
} __attribute__((packed));
struct _tga_footer
{
unsigned int extensionAreaOffset;
unsigned int developerDirectoryOffset;
char signature[16];
char dot;
char null;
} __attribute__((packed));
static Eina_Bool
evas_image_load_file_head_tga(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
Eina_File *f;
unsigned char *seg = NULL, *filedata;
tga_header *header;
tga_footer *footer, tfooter;
char hasa = 0;
int w = 0, h = 0, bpp;
int x, y;
f = eina_file_open(file, EINA_FALSE);
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
if (f == NULL) return EINA_FALSE;
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
if (eina_file_size_get(f) < (off_t)(sizeof(tga_header) + sizeof(tga_footer)))
goto close_file;
seg = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
if (seg == NULL) goto close_file;
filedata = seg;
header = (tga_header *)filedata;
// no unaligned data accessed, so ok
footer = (tga_footer *)(filedata + (eina_file_size_get(f) - sizeof(tga_footer)));
memcpy((unsigned char *)(&tfooter),
(unsigned char *)footer,
sizeof(tga_footer));
//printf("0\n");
if (!memcmp(tfooter.signature, TGA_SIGNATURE, sizeof(tfooter.signature)))
{
if ((tfooter.dot == '.') && (tfooter.null == 0))
{
// footer is there and matches. this is a tga file - any problems now
// are a corrupt file
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
}
}
// else goto close_file;
//printf("1\n");
filedata = (unsigned char *)filedata + sizeof(tga_header);
switch (header->imageType)
{
case TGA_TYPE_COLOR_RLE:
case TGA_TYPE_GRAY_RLE:
// rle = 1;
break;
case TGA_TYPE_COLOR:
case TGA_TYPE_GRAY:
// rle = 0;
break;
default:
goto close_file;
}
bpp = header->bpp;
if (!((bpp == 32) || (bpp == 24) || (bpp == 16) || (bpp == 8)))
goto close_file;
if ((bpp == 32) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
// don't handle colormapped images
if ((header->colorMapType) != 0)
goto close_file;
// if colormap size is anything other than legal sizes or 0 - not real tga
if (!((header->colorMapSize == 0) ||
(header->colorMapSize == 15) ||
(header->colorMapSize == 16) ||
(header->colorMapSize == 24) ||
(header->colorMapSize == 32)))
goto close_file;
x = (header->xOriginHi << 8) | (header->xOriginLo);
y = (header->yOriginHi << 8) | (header->yOriginLo);
w = (header->widthHi << 8) | header->widthLo;
h = (header->heightHi << 8) | header->heightLo;
// x origin gerater that width, y origin greater than height - wrong file
if ((x >= w) || (y >= h))
goto close_file;
// if descriptor has either of the top 2 bits set... not tga
if (header->descriptor & 0xc0)
goto close_file;
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
goto close_file;
ilp->w = w;
ilp->h = h;
if (hasa) ilp->alpha = 1;
eina_file_map_free(f, seg);
eina_file_close(f);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
close_file:
if (seg != NULL) eina_file_map_free(f, seg);
eina_file_close(f);
return EINA_FALSE;
}
static Eina_Bool
evas_image_load_file_data_tga(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
Eina_File *f;
unsigned char *seg = NULL, *filedata;
tga_header *header;
tga_footer *footer, tfooter;
char hasa = 0, footer_present = 0, vinverted = 0, rle = 0;
int w = 0, h = 0, x, y, bpp;
off_t size;
unsigned int *surface, *dataptr;
unsigned int datasize;
unsigned char *bufptr, *bufend;
int abits;
f = eina_file_open(file, EINA_FALSE);
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
if (f == NULL) return EINA_FALSE;
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
if (eina_file_size_get(f) < (off_t)(sizeof(tga_header) + sizeof(tga_footer)))
goto close_file;
seg = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
if (seg == NULL) goto close_file;
filedata = seg;
size = eina_file_size_get(f);
header = (tga_header *)filedata;
// no unaligned data accessed, so ok
footer = (tga_footer *)(filedata + (size - sizeof(tga_footer)));
memcpy((unsigned char *)&tfooter,
(unsigned char *)footer,
sizeof(tga_footer));
if (!memcmp(tfooter.signature, TGA_SIGNATURE, sizeof(tfooter.signature)))
{
if ((tfooter.dot == '.') && (tfooter.null == 0))
{
// footer is there and matches. this is a tga file - any problems now
// are a corrupt file
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
footer_present = 1;
}
}
filedata = (unsigned char *)filedata + sizeof(tga_header);
vinverted = !(header->descriptor & TGA_DESC_VERTICAL);
switch (header->imageType)
{
case TGA_TYPE_COLOR_RLE:
case TGA_TYPE_GRAY_RLE:
rle = 1;
break;
case TGA_TYPE_COLOR:
case TGA_TYPE_GRAY:
rle = 0;
break;
default:
goto close_file;
}
bpp = header->bpp;
if (!((bpp == 32) || (bpp == 24) || (bpp == 16) || (bpp == 8)))
goto close_file;
if ((bpp == 32) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
abits = header->descriptor & TGA_DESC_ABITS;
// don't handle colormapped images
if ((header->colorMapType) != 0)
goto close_file;
// if colormap size is anything other than legal sizes or 0 - not real tga
if (!((header->colorMapSize == 0) ||
(header->colorMapSize == 15) ||
(header->colorMapSize == 16) ||
(header->colorMapSize == 24) ||
(header->colorMapSize == 32)))
goto close_file;
x = (header->xOriginHi << 8) | (header->xOriginLo);
y = (header->yOriginHi << 8) | (header->yOriginLo);
w = (header->widthHi << 8) | header->widthLo;
h = (header->heightHi << 8) | header->heightLo;
// x origin gerater that width, y origin greater than height - wrong file
if ((x >= w) || (y >= h))
goto close_file;
// if descriptor has either of the top 2 bits set... not tga
if (header->descriptor & 0xc0)
goto close_file;
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
goto close_file;
if ((w != (int)ilp->w) || (h != (int)ilp->h))
{
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
surface = ilp->buffer;
if (!surface)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
datasize = size - sizeof(tga_header) - header->idLength;
if (footer_present)
datasize = size - sizeof(tga_header) - header->idLength -
sizeof(tga_footer);
bufptr = filedata + header->idLength;
bufend = filedata + datasize;
if (!rle)
{
for (y = 0; y < h; y++)
{
if (vinverted)
/* some TGA's are stored upside-down! */
dataptr = surface + ((h - y - 1) * w);
else
dataptr = surface + (y * w);
switch (bpp)
{
case 32:
for (x = 0; (x < w) && ((bufptr + 4) <= bufend); x++)
{
if (hasa)
{
int a = bufptr[3];
switch (abits)
{
case 1:
a = (a << 7) | (a << 6) | (a << 5) | (a << 4) | (a << 3) | (a << 2) | (a << 1) | (a);
case 2:
a = (a << 6) | (a << 4) | (a << 2) | (a);
case 3:
a = (a << 5) | (a << 2) | (a >> 1);
case 4:
a = (a << 4) | (a);
case 5:
a = (a << 3) | (a >> 2);
case 6:
a = (a << 2) | (a >> 4);
case 7:
a = (a << 1) | (a >> 6);
default:
break;
}
*dataptr = ARGB_JOIN(a, bufptr[2], bufptr[1], bufptr[0]);
}
else
*dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
dataptr++;
bufptr += 4;
}
break;
case 24:
for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
{
*dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
dataptr++;
bufptr += 3;
}
break;
case 16:
for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
{
unsigned char r, g, b, a;
unsigned short tmp;
tmp =
(((unsigned short)bufptr[1]) << 8) |
(((unsigned short)bufptr[0]));
r = (tmp >> 7) & 0xf8; r |= r >> 5;
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
a = 0xff;
if ((hasa) && (tmp & 0x8000)) a = 0;
*dataptr = ARGB_JOIN(a, r, g, b);
dataptr++;
bufptr += 2;
}
break;
case 8:
for (x = 0; (x < w) && ((bufptr + 1) <= bufend); x++)
{
*dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[0], bufptr[0]);
dataptr++;
bufptr += 1;
}
break;
default:
break;
}
}
}
else
{
int count, i;
unsigned char val;
unsigned int *dataend;
dataptr = surface;
dataend = dataptr + (w * h);
while ((bufptr < bufend) && (dataptr < dataend))
{
val = *bufptr;
bufptr++;
count = (val & 0x7f) + 1;
if (val & 0x80) // rel packet
{
switch (bpp)
{
case 32:
if (bufptr < (bufend - 4))
{
unsigned char r, g, b;
int a = bufptr[3];
switch (abits)
{
case 1:
a = (a << 7) | (a << 6) | (a << 5) | (a << 4) | (a << 3) | (a << 2) | (a << 1) | (a);
case 2:
a = (a << 6) | (a << 4) | (a << 2) | (a);
case 3:
a = (a << 5) | (a << 2) | (a >> 1);
case 4:
a = (a << 4) | (a);
case 5:
a = (a << 3) | (a >> 2);
case 6:
a = (a << 2) | (a >> 4);
case 7:
a = (a << 1) | (a >> 6);
default:
break;
}
r = bufptr[2];
g = bufptr[1];
b = bufptr[0];
if (!hasa) a = 0xff;
bufptr += 4;
for (i = 0; (i < count) && (dataptr < dataend); i++)
{
*dataptr = ARGB_JOIN(a, r, g, b);
dataptr++;
}
}
break;
case 24:
if (bufptr < (bufend - 3))
{
unsigned char r, g, b;
r = bufptr[2];
g = bufptr[1];
b = bufptr[0];
bufptr += 3;
for (i = 0; (i < count) && (dataptr < dataend); i++)
{
*dataptr = ARGB_JOIN(0xff, r, g, b);
dataptr++;
}
}
break;
case 16:
if (bufptr < (bufend - 2))
{
unsigned char r, g, b, a;
unsigned short tmp;
tmp =
(((unsigned short)bufptr[1]) << 8) |
(((unsigned short)bufptr[0]));
r = (tmp >> 7) & 0xf8; r |= r >> 5;
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
a = 0xff;
if ((hasa) && (tmp & 0x8000)) a = 0;
bufptr += 2;
for (i = 0; (i < count) && (dataptr < dataend); i++)
{
*dataptr = ARGB_JOIN(a, r, g, b);
dataptr++;
}
}
break;
case 8:
if (bufptr < (bufend - 1))
{
unsigned char g;
g = bufptr[0];
bufptr += 1;
for (i = 0; (i < count) && (dataptr < dataend); i++)
{
*dataptr = ARGB_JOIN(0xff, g, g, g);
dataptr++;
}
}
break;
default:
break;
}
}
else // raw
{
switch (bpp)
{
case 32:
for (i = 0; (i < count) && (bufptr < (bufend - 4)) && (dataptr < dataend); i++)
{
if (hasa)
// *dataptr = ARGB_JOIN(255 - bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
*dataptr = ARGB_JOIN(bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
else
*dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
dataptr++;
bufptr += 4;
}
break;
case 24:
for (i = 0; (i < count) && (bufptr < (bufend - 3)) && (dataptr < dataend); i++)
{
*dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
dataptr++;
bufptr += 3;
}
break;
case 16:
for (i = 0; (i < count) && (bufptr < (bufend - 2)) && (dataptr < dataend); i++)
{
unsigned char r, g, b, a;
unsigned short tmp;
tmp =
(((unsigned short)bufptr[1]) << 8) |
(((unsigned short)bufptr[0]));
r = (tmp >> 7) & 0xf8; r |= r >> 5;
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
a = 0xff;
if ((hasa) && (tmp & 0x8000)) a = 0;
*dataptr = ARGB_JOIN(a, r, g, b);
dataptr++;
bufptr += 2;
}
break;
case 8:
for (i = 0; (i < count) && (bufptr < (bufend - 1)) && (dataptr < dataend); i++)
{
*dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[0], bufptr[0]);
dataptr++;
bufptr += 1;
}
break;
default:
break;
}
}
}
if (vinverted)
{
unsigned int *adv, *adv2, tmp;
adv = surface;
adv2 = surface + (w * (h - 1));
for (y = 0; y < (h / 2); y++)
{
for (x = 0; x < w; x++)
{
tmp = adv[x];
adv[x] = adv2[x];
adv2[x] = tmp;
}
adv2 -= w;
adv += w;
}
}
}
evas_cserve2_image_premul(ilp);
eina_file_map_free(f, seg);
eina_file_close(f);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
close_file:
if (seg != NULL) eina_file_map_free(f, seg);
eina_file_close(f);
return EINA_FALSE;
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"tga",
evas_image_load_file_head_tga,
evas_image_load_file_data_tga
};
static Eina_Bool
module_init(void)
{
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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

View File

@ -0,0 +1,282 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <tiffio.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
typedef struct TIFFRGBAImage_Extra TIFFRGBAImage_Extra;
struct TIFFRGBAImage_Extra {
TIFFRGBAImage rgba;
char pper;
uint32 num_pixels;
uint32 py;
};
static Eina_Bool
evas_image_load_file_head_tiff(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
char txt[1024];
TIFFRGBAImage tiff_image;
TIFF *tif = NULL;
FILE *ffile;
int fd;
uint16 magic_number;
ffile = fopen(file, "rb");
if (!ffile)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
if (fread(&magic_number, sizeof(uint16), 1, ffile) != 1)
{
fclose(ffile);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
/* Apparently rewind(f) isn't sufficient */
fseek(ffile, 0, SEEK_SET);
if ((magic_number != TIFF_BIGENDIAN) /* Checks if actually tiff file */
&& (magic_number != TIFF_LITTLEENDIAN))
{
fclose(ffile);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
fd = fileno(ffile);
fd = dup(fd);
lseek(fd, (long)0, SEEK_SET);
fclose(ffile);
tif = TIFFFdOpen(fd, file, "r");
if (!tif)
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
strcpy(txt, "Evas Tiff loader: cannot be processed by libtiff");
if (!TIFFRGBAImageOK(tif, txt))
{
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
strcpy(txt, "Evas Tiff loader: cannot begin reading tiff");
if (!TIFFRGBAImageBegin(& tiff_image, tif, 1, txt))
{
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
if (tiff_image.alpha != EXTRASAMPLE_UNSPECIFIED)
ilp->alpha = 1;
if ((tiff_image.width < 1) || (tiff_image.height < 1) ||
(tiff_image.width > IMG_MAX_SIZE) || (tiff_image.height > IMG_MAX_SIZE) ||
IMG_TOO_BIG(tiff_image.width, tiff_image.height))
{
TIFFClose(tif);
if (IMG_TOO_BIG(tiff_image.width, tiff_image.height))
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
else
*error = EVAS_LOAD_ERROR_GENERIC;
return EINA_FALSE;
}
ilp->w = tiff_image.width;
ilp->h = tiff_image.height;
TIFFRGBAImageEnd(&tiff_image);
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
}
static Eina_Bool
evas_image_load_file_data_tiff(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
char txt[1024];
TIFFRGBAImage_Extra rgba_image;
TIFF *tif = NULL;
FILE *ffile;
uint32 *rast = NULL;
uint32 num_pixels;
int fd, x, y;
uint16 magic_number;
unsigned int *surface;
ffile = fopen(file, "rb");
if (!ffile)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
if (fread(&magic_number, sizeof(uint16), 1, ffile) != 1)
{
fclose(ffile);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
/* Apparently rewind(f) isn't sufficient */
fseek(ffile, (long)0, SEEK_SET);
if ((magic_number != TIFF_BIGENDIAN) /* Checks if actually tiff file */
&& (magic_number != TIFF_LITTLEENDIAN))
{
fclose(ffile);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
fd = fileno(ffile);
fd = dup(fd);
lseek(fd, (long)0, SEEK_SET);
fclose(ffile);
tif = TIFFFdOpen(fd, file, "r");
if (!tif)
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
strcpy(txt, "Evas Tiff loader: cannot be processed by libtiff");
if (!TIFFRGBAImageOK(tif, txt))
{
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
strcpy(txt, "Evas Tiff loader: cannot begin reading tiff");
if (!TIFFRGBAImageBegin((TIFFRGBAImage *) & rgba_image, tif, 0, txt))
{
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
if (rgba_image.rgba.alpha != EXTRASAMPLE_UNSPECIFIED)
ilp->alpha = 1;
if ((rgba_image.rgba.width != ilp->w) ||
(rgba_image.rgba.height != ilp->h))
{
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return EINA_FALSE;
}
surface = ilp->buffer;
if (!surface)
{
TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return EINA_FALSE;
}
rgba_image.num_pixels = num_pixels = ilp->w * ilp->h;
rgba_image.pper = rgba_image.py = 0;
rast = (uint32 *) _TIFFmalloc(sizeof(uint32) * num_pixels);
if (!rast)
{
ERR("Evas Tiff loader: out of memory");
TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return EINA_FALSE;
}
if (rgba_image.rgba.bitspersample == 8)
{
if (!TIFFRGBAImageGet((TIFFRGBAImage *) &rgba_image, rast,
rgba_image.rgba.width, rgba_image.rgba.height))
{
_TIFFfree(rast);
TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
TIFFClose(tif);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
}
/* process rast -> image rgba. really same as prior code anyway just simpler */
for (y = 0; y < (int)ilp->h; y++)
{
DATA32 *pix, *pd;
uint32 *ps, pixel;
unsigned int a, r, g, b;
pix = surface;
pd = pix + ((ilp->h - y - 1) * ilp->w);
ps = rast + (y * ilp->w);
for (x = 0; x < (int)ilp->w; x++)
{
pixel = *ps;
a = TIFFGetA(pixel);
r = TIFFGetR(pixel);
g = TIFFGetG(pixel);
b = TIFFGetB(pixel);
if (!ilp->alpha) a = 255;
if ((rgba_image.rgba.alpha == EXTRASAMPLE_UNASSALPHA) &&
(a < 255))
{
r = (r * (a + 1)) >> 8;
g = (g * (a + 1)) >> 8;
b = (b * (a + 1)) >> 8;
}
*pd = ARGB_JOIN(a, r, g, b);
ps++;
pd++;
}
}
_TIFFfree(rast);
TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
TIFFClose(tif);
evas_cserve2_image_alpha_sparse_set(ilp);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"tiff",
evas_image_load_file_head_tiff,
evas_image_load_file_data_tiff
};
static Eina_Bool
module_init(void)
{
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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

View File

@ -0,0 +1,189 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
static int
read_mb(unsigned int *data, void *map, size_t length, size_t *position)
{
int ac = 0, ct;
unsigned char buf;
for (ct = 0;;)
{
if ((ct++) == 5) return -1;
if (*position > length) return -1;
buf = ((unsigned char *) map)[(*position)++];
ac = (ac << 7) | (buf & 0x7f);
if ((buf & 0x80) == 0) break;
}
*data = ac;
return 0;
}
static Eina_Bool
evas_image_load_file_head_wbmp(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
Eina_File *f;
void *map = NULL;
size_t position = 0;
size_t length;
unsigned int type, w, h;
*error = EVAS_LOAD_ERROR_GENERIC;
f = eina_file_open(file, 0);
if (!f)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
length = eina_file_size_get(f);
if (length <= 4) goto bail;
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
if (!map) goto bail;
if (read_mb(&type, map, length, &position) < 0) goto bail;
if (type != 0)
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto bail;
}
position++; /* skipping one byte */
if (read_mb(&w, map, length, &position) < 0) goto bail;
if (read_mb(&h, map, length, &position) < 0) goto bail;
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto bail;
}
eina_file_map_free(f, map);
eina_file_close(f);
ilp->w = w;
ilp->h = h;
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
bail:
if (map) eina_file_map_free(f, map);
eina_file_close(f);
return EINA_FALSE;
}
static Eina_Bool
evas_image_load_file_data_wbmp(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int *error)
{
Eina_File *f;
void *map = NULL;
size_t position = 0;
size_t length;
unsigned int type, w, h;
unsigned int line_length;
unsigned char *line = NULL;
int cur = 0, x, y;
DATA32 *dst_data;
*error = EVAS_LOAD_ERROR_GENERIC;
f = eina_file_open(file, EINA_FALSE);
if (!f)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
length = eina_file_size_get(f);
if (length <= 4) goto bail;
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
if (!map) goto bail;
if (read_mb(&type, map, length, &position) < 0) goto bail;
position++; /* skipping one byte */
if (read_mb(&w, map, length, &position) < 0) goto bail;
if (read_mb(&h, map, length, &position) < 0) goto bail;
if (type != 0)
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto bail;
}
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto bail;
}
ilp->w = w;
ilp->h = h;
dst_data = ilp->buffer;
if (!dst_data)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto bail;
}
line_length = (ilp->w + 7) >> 3;
for (y = 0; y < (int)ilp->h; y++)
{
if (position + line_length > length) goto bail;
line = ((unsigned char*) map) + position;
position += line_length;
for (x = 0; x < (int)ilp->w; x++)
{
int idx = x >> 3;
int offset = 1 << (0x07 - (x & 0x07));
if (line[idx] & offset) dst_data[cur] = 0xffffffff;
else dst_data[cur] = 0xff000000;
cur++;
}
}
eina_file_map_free(f, map);
eina_file_close(f);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
bail:
if (map) eina_file_map_free(f, map);
eina_file_close(f);
return EINA_FALSE;
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"wbmp",
evas_image_load_file_head_wbmp,
evas_image_load_file_data_wbmp
};
static Eina_Bool
module_init(void)
{
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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

View File

@ -0,0 +1,650 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_macros.h"
#include "evas_cserve2.h"
#include "evas_cserve2_slave.h"
static Eina_File *rgb_txt;
static void *rgb_txt_map;
static void
xpm_parse_color(char *color, int *r, int *g, int *b)
{
char *tmp;
char *max;
char *endline;
char buf[4096];
/* is a #ff00ff like color */
if (color[0] == '#')
{
int len;
char val[32];
len = strlen(color) - 1;
if (len < 96)
{
int i;
len /= 3;
for (i = 0; i < len; i++)
val[i] = color[1 + i + (0 * len)];
val[i] = 0;
sscanf(val, "%x", r);
for (i = 0; i < len; i++)
val[i] = color[1 + i + (1 * len)];
val[i] = 0;
sscanf(val, "%x", g);
for (i = 0; i < len; i++)
val[i] = color[1 + i + (2 * len)];
val[i] = 0;
sscanf(val, "%x", b);
if (len == 1)
{
*r = (*r << 4) | *r;
*g = (*g << 4) | *g;
*b = (*b << 4) | *b;
}
else if (len > 2)
{
*r >>= (len - 2) * 4;
*g >>= (len - 2) * 4;
*b >>= (len - 2) * 4;
}
}
return;
}
/* look in rgb txt database */
if (!rgb_txt) return;
tmp = rgb_txt_map;
max = tmp + eina_file_size_get(rgb_txt);
while (tmp < max)
{
endline = memchr(tmp, '\n', max - tmp);
if (!endline) endline = max;
if ((*tmp != '!') && ((endline - tmp) < (int) (sizeof(buf) - 1)))
{
int rr, gg, bb;
char name[4096];
/* FIXME: not really efficient */
memcpy(buf, tmp, endline - tmp);
buf[endline - tmp + 1] = '\0';
if (sscanf(buf, "%i %i %i %[^\n]", &rr, &gg, &bb, name) == 4)
{
if (!strcasecmp(name, color))
{
*r = rr;
*g = gg;
*b = bb;
return;
}
}
}
tmp = endline + 1;
}
}
/** FIXME: clean this up and make more efficient **/
static Eina_Bool
evas_image_load_file_xpm(Evas_Img_Load_Params *ilp, const char *file, const char *key __UNUSED__, int load_data, int *error)
{
DATA32 *ptr, *end;
Eina_File *f;
const char *map;
size_t length;
size_t position;
int pc, c, i, j, k, w, h, ncolors, cpp, comment, transp,
quote, context, len, done, r, g, b, backslash, lu1, lu2;
char *line = NULL;
char s[256], tok[128], col[256], *tl;
int lsz = 256;
struct _cmap {
char str[6];
unsigned char transp;
short r, g, b;
} *cmap = NULL;
short lookup[128 - 32][128 - 32];
int count, pixels;
done = 0;
// transp = -1;
transp = 1;
/* if immediate_load is 1, then dont delay image laoding as below, or */
/* already data in this image - dont load it again */
f = eina_file_open(file, 0);
if (!f)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
length = eina_file_size_get(f);
position = 0;
if (length < 9)
{
eina_file_close(f);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
if (!map)
{
eina_file_close(f);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
if (strncmp("/* XPM */", map, 9))
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto on_error;
}
i = 0;
j = 0;
cmap = NULL;
w = 10;
h = 10;
ptr = NULL;
end = NULL;
c = ' ';
comment = 0;
quote = 0;
context = 0;
pixels = 0;
count = 0;
line = malloc(lsz);
if (!line)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto on_error;
}
backslash = 0;
memset(lookup, 0, sizeof(lookup));
while (!done)
{
pc = c;
if (position == length) break ;
c = (char) map[position++];
if (!quote)
{
if ((pc == '/') && (c == '*'))
comment = 1;
else if ((pc == '*') && (c == '/') && (comment))
comment = 0;
}
if (!comment)
{
if ((!quote) && (c == '"'))
{
quote = 1;
i = 0;
}
else if ((quote) && (c == '"'))
{
line[i] = 0;
quote = 0;
if (context == 0)
{
/* Header */
if (sscanf(line, "%i %i %i %i", &w, &h, &ncolors, &cpp) != 4)
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
goto on_error;
}
if ((ncolors > 32766) || (ncolors < 1))
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto on_error;
}
if ((cpp > 5) || (cpp < 1))
{
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto on_error;
}
if ((w > IMG_MAX_SIZE) || (w < 1))
{
*error = EVAS_LOAD_ERROR_GENERIC;
goto on_error;
}
if ((h > IMG_MAX_SIZE) || (h < 1))
{
*error = EVAS_LOAD_ERROR_GENERIC;
goto on_error;
}
if (IMG_TOO_BIG(w, h))
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto on_error;
}
if (!cmap)
{
cmap = malloc(sizeof(struct _cmap) * ncolors);
if (!cmap)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto on_error;
}
}
ilp->w = w;
ilp->h = h;
j = 0;
context++;
}
else if (context == 1)
{
/* Color Table */
if (j < ncolors)
{
int slen;
int hascolor, iscolor;
iscolor = 0;
hascolor = 0;
tok[0] = 0;
col[0] = 0;
s[0] = 0;
len = strlen(line);
strncpy(cmap[j].str, line, cpp);
cmap[j].str[cpp] = 0;
for (slen = 0; slen < cpp; slen++)
{
/* fix the ascii of the color string - if its < 32 - just limit to 32 */
if (cmap[j].str[slen] < 32) cmap[j].str[slen] = 0;
}
cmap[j].r = -1;
cmap[j].transp = 0;
for (k = cpp; k < len; k++)
{
if (line[k] != ' ')
{
s[0] = 0;
sscanf(&line[k], "%255s", s);
slen = strlen(s);
k += slen;
if (!strcmp(s, "c")) iscolor = 1;
if ((!strcmp(s, "m")) || (!strcmp(s, "s"))
|| (!strcmp(s, "g4")) || (!strcmp(s, "g"))
|| (!strcmp(s, "c")) || (k >= len))
{
if (k >= len)
{
if (col[0])
{
if (strlen(col) < (sizeof(col) - 2))
strcat(col, " ");
else
done = 1;
}
if ((strlen(col) + strlen(s)) < (sizeof(col) - 1))
strcat(col, s);
}
if (col[0])
{
if (!strcasecmp(col, "none"))
{
transp = 1;
cmap[j].transp = 1;
cmap[j].r = 0;
cmap[j].g = 0;
cmap[j].b = 0;
}
else
{
if ((((cmap[j].r < 0) || (!strcmp(tok, "c"))) && (!hascolor)))
{
r = g = b = 0;
xpm_parse_color(col, &r, &g, &b);
cmap[j].r = r;
cmap[j].g = g;
cmap[j].b = b;
if (iscolor) hascolor = 1;
}
}
}
strcpy(tok, s);
col[0] = 0;
}
else
{
if (col[0])
{
if (strlen(col) < ( sizeof(col) - 2))
strcat(col, " ");
else
done = 1;
}
if ((strlen(col) + strlen(s)) < (sizeof(col) - 1))
strcat(col, s);
}
}
}
}
j++;
if (j >= ncolors)
{
if (cpp == 1)
{
for (i = 0; i < ncolors; i++)
lookup[(int)cmap[i].str[0] - 32][0] = i;
}
if (cpp == 2)
{
for (i = 0; i < ncolors; i++)
lookup[(int)cmap[i].str[0] - 32][(int)cmap[i].str[1] - 32] = i;
}
context++;
}
if (transp) ilp->alpha = 1;
if (load_data)
{
ptr = ilp->buffer;
if (!ptr)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto on_error;
}
pixels = w * h;
end = ptr + pixels;
}
else
{
*error = EVAS_LOAD_ERROR_NONE;
goto on_success;
}
}
else
{
/* Image Data */
i = 0;
if (cpp == 0)
{
/* Chars per pixel = 0? well u never know */
}
/* it's xpm - don't care about speed too much. still faster
* that most xpm loaders anyway */
else if (cpp == 1)
{
if (transp)
{
for (i = 0;
((i < 65536) && (ptr < end) && (line[i]));
i++)
{
lu1 = (int)line[i] - 32;
if (lu1 < 0) continue;
if (cmap[lookup[lu1][0]].transp)
{
r = (unsigned char)cmap[lookup[lu1][0]].r;
g = (unsigned char)cmap[lookup[lu1][0]].g;
b = (unsigned char)cmap[lookup[lu1][0]].b;
*ptr = RGB_JOIN(r, g, b);
ptr++;
count++;
}
else
{
r = (unsigned char)cmap[lookup[lu1][0]].r;
g = (unsigned char)cmap[lookup[lu1][0]].g;
b = (unsigned char)cmap[lookup[lu1][0]].b;
*ptr = ARGB_JOIN(0xff, r, g, b);
ptr++;
count++;
}
}
}
else
{
for (i = 0;
((i < 65536) && (ptr < end) && (line[i]));
i++)
{
lu1 = (int)line[i] - 32;
if (lu1 < 0) continue;
r = (unsigned char)cmap[lookup[lu1][0]].r;
g = (unsigned char)cmap[lookup[lu1][0]].g;
b = (unsigned char)cmap[lookup[lu1][0]].b;
*ptr = ARGB_JOIN(0xff, r, g, b);
ptr++;
count++;
}
}
}
else if (cpp == 2)
{
if (transp)
{
for (i = 0;
((i < 65536) && (ptr < end) && (line[i]));
i++)
{
lu1 = (int)line[i] - 32;
i++;
lu2 = (int)line[i] - 32;
if (lu1 < 0) continue;
if (lu2 < 0) continue;
if (cmap[lookup[lu1][lu2]].transp)
{
r = (unsigned char)cmap[lookup[lu1][lu2]].r;
g = (unsigned char)cmap[lookup[lu1][lu2]].g;
b = (unsigned char)cmap[lookup[lu1][lu2]].b;
*ptr = RGB_JOIN(r, g, b);
ptr++;
count++;
}
else
{
r = (unsigned char)cmap[lookup[lu1][lu2]].r;
g = (unsigned char)cmap[lookup[lu1][lu2]].g;
b = (unsigned char)cmap[lookup[lu1][lu2]].b;
*ptr = ARGB_JOIN(0xff, r, g, b);
ptr++;
count++;
}
}
}
else
{
for (i = 0;
((i < 65536) && (ptr < end) && (line[i]));
i++)
{
lu1 = (int)line[i] - 32;
i++;
lu2 = (int)line[i] - 32;
if (lu1 < 0) continue;
if (lu2 < 0) continue;
r = (unsigned char)cmap[lookup[lu1][lu2]].r;
g = (unsigned char)cmap[lookup[lu1][lu2]].g;
b = (unsigned char)cmap[lookup[lu1][lu2]].b;
*ptr = ARGB_JOIN(0xff, r, g, b);
ptr++;
count++;
}
}
}
else
{
if (transp)
{
for (i = 0;
((i < 65536) && (ptr < end) && (line[i]));
i++)
{
for (j = 0; j < cpp; j++, i++)
{
col[j] = line[i];
if (col[j] < 32) col[j] = 32;
}
col[j] = 0;
i--;
for (j = 0; j < ncolors; j++)
{
if (!strcmp(col, cmap[j].str))
{
if (cmap[j].transp)
{
r = (unsigned char)cmap[j].r;
g = (unsigned char)cmap[j].g;
b = (unsigned char)cmap[j].b;
*ptr = RGB_JOIN(r, g, b);
ptr++;
count++;
}
else
{
r = (unsigned char)cmap[j].r;
g = (unsigned char)cmap[j].g;
b = (unsigned char)cmap[j].b;
*ptr = ARGB_JOIN(0xff, r, g, b);
ptr++;
count++;
}
break;
}
}
}
}
else
{
for (i = 0;
((i < 65536) && (ptr < end) && (line[i]));
i++)
{
for (j = 0; j < cpp; j++, i++)
{
col[j] = line[i];
}
col[j] = 0;
i--;
for (j = 0; j < ncolors; j++)
{
if (!strcmp(col, cmap[j].str))
{
r = (unsigned char)cmap[j].r;
g = (unsigned char)cmap[j].g;
b = (unsigned char)cmap[j].b;
*ptr = ARGB_JOIN(0xff, r, g, b);
ptr++;
count++;
break;
}
}
}
}
}
}
}
}
/* Scan in line from XPM file */
if ((!comment) && (quote) && (c != '"'))
{
if (c < 32) c = 32;
else if (c > 127) c = 127;
if (c =='\\')
{
if (++backslash < 2)
line[i++] = c;
else
backslash = 0;
}
else
{
backslash = 0;
line[i++] = c;
}
}
if (i >= lsz)
{
lsz += 256;
tl = realloc(line, lsz);
if (!tl) break;
line = tl;
}
if (((ptr) && ((ptr - (DATA32 *)ilp->buffer) >= (w * h * (int)sizeof(DATA32)))) ||
((context > 1) && (count >= pixels)))
break;
}
on_success:
free(cmap);
free(line);
eina_file_map_free(f, (void*) map);
eina_file_close(f);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
on_error:
free(line);
eina_file_map_free(f, (void*) map);
eina_file_close(f);
return EINA_FALSE;
}
static Eina_Bool
evas_image_load_file_head_xpm(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
{
return evas_image_load_file_xpm(ilp, file, key, 0, error);
}
static Eina_Bool
evas_image_load_file_data_xpm(Evas_Img_Load_Params *ilp, const char *file, const char *key, int *error)
{
return evas_image_load_file_xpm(ilp, file, key, 1, error);
}
static Evas_Loader_Module_Api modapi =
{
EVAS_CSERVE2_MODULE_API_VERSION,
"xpm",
evas_image_load_file_head_xpm,
evas_image_load_file_data_xpm
};
static Eina_Bool
module_init(void)
{
/* Shouldn't we make that PATH configurable ? */
rgb_txt = eina_file_open("/usr/lib/X11/rgb.txt", 0);
if (!rgb_txt) rgb_txt = eina_file_open("/usr/X11/lib/X11/rgb.txt", 0);
if (!rgb_txt) rgb_txt = eina_file_open("/usr/X11R6/lib/X11/rgb.txt", 0);
if (!rgb_txt) rgb_txt = eina_file_open("/usr/openwin/lib/X11/rgb.txt", 0);
if (rgb_txt)
rgb_txt_map = eina_file_map_all(rgb_txt, EINA_FILE_SEQUENTIAL);
return evas_cserve2_loader_register(&modapi);
}
static void
module_shutdown(void)
{
if (rgb_txt)
{
eina_file_map_free(rgb_txt, rgb_txt_map);
eina_file_close(rgb_txt);
rgb_txt = NULL;
}
}
EINA_MODULE_INIT(module_init);
EINA_MODULE_SHUTDOWN(module_shutdown);

View File

@ -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 \

View File

@ -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 <Ecore.h>
#include <Ecore_Evas.h>
#include <stdio.h>
#include <errno.h>
#define WIDTH (320)
#define HEIGHT (240)
static const char *img_path = PACKAGE_EXAMPLES_DIR "/enlightenment.png";
static const char *commands = \
"commands are:\n"
"\tw - write new pixel data to image\n"
"\ti - print image info\n"
"\ta - save noise image to disk (/tmp dir)\n"
"\th - print help\n";
const char *file_path = "/tmp/evas-images2-example.png";
const char *quality_str = "quality=100";
struct test_data
{
Ecore_Evas *ee;
Evas *evas;
Evas_Object *bg;
Evas_Object *logo, *logo1;
};
static struct test_data d = {0};
static void
_on_destroy(Ecore_Evas *ee __UNUSED__)
{
ecore_main_loop_quit();
}
/* here just to keep our example's window size and background image's
* size in synchrony */
static void
_canvas_resize_cb(Ecore_Evas *ee)
{
int w, h;
ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
evas_object_resize(d.bg, w, h);
evas_object_resize(d.logo, w / 2, h);
evas_object_move(d.logo1, w / 2, 0);
evas_object_resize(d.logo1, w / 2, h);
}
static void
_on_keydown(void *data __UNUSED__,
Evas *evas __UNUSED__,
Evas_Object *o __UNUSED__,
void *einfo)
{
Evas_Event_Key_Down *ev = einfo;
if (strcmp(ev->keyname, "h") == 0) /* print help */
{
fprintf(stdout, commands);
return;
}
if (strcmp(ev->keyname, "i") == 0) /* change proxy's source */
{
int stride = evas_object_image_stride_get(d.logo);
int w, h;
evas_object_image_size_get(d.logo, &w, &h);
printf("image size: %dx%d; stride: %d\n", w, h, stride);
return;
}
if (strcmp(ev->keyname, "w") == 0) /* save noise image to disk */
{
int i;
char *pixels = evas_object_image_data_get(d.logo, EINA_FALSE);
char *bufpixels;
int w, h;
int stride;
Eina_Bool equal = EINA_TRUE;
evas_object_image_size_get(d.logo, &w, &h);
stride = evas_object_image_stride_get(d.logo);
bufpixels = malloc(sizeof(char) * stride * h);
memcpy(bufpixels, pixels, sizeof(char) * stride * h);
pixels = evas_object_image_data_get(d.logo, EINA_TRUE);
for (i = 0; i < (stride * h); i++)
{
if (bufpixels[i] != pixels[i])
{
equal = EINA_FALSE;
break;
}
}
free(bufpixels);
if (!equal)
printf("write pixels different from readonly pixels.\n");
for (i = ((stride * h) / 4) ; i < ((stride * h) / 2) ; i++)
{
pixels[i] = 0;
}
// evas_object_image_data_set(d.logo, pixels);
evas_object_image_data_update_add(d.logo, 0, 0, w, h);
return;
}
}
int
main(void)
{
// unsigned int i;
// unsigned int pixels[(WIDTH / 4) * (HEIGHT / 4)];
if (!ecore_evas_init())
return EXIT_FAILURE;
/* this will give you a window with an Evas canvas under the first
* engine available */
d.ee = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL);
if (!d.ee)
goto error;
ecore_evas_callback_destroy_set(d.ee, _on_destroy);
ecore_evas_callback_resize_set(d.ee, _canvas_resize_cb);
ecore_evas_show(d.ee);
/* the canvas pointer, de facto */
d.evas = ecore_evas_get(d.ee);
d.bg = evas_object_rectangle_add(d.evas);
evas_object_color_set(d.bg, 255, 255, 255, 255); /* white bg */
evas_object_move(d.bg, 0, 0); /* at canvas' origin */
evas_object_resize(d.bg, WIDTH, HEIGHT); /* covers full canvas */
evas_object_show(d.bg);
evas_object_focus_set(d.bg, EINA_TRUE);
evas_object_event_callback_add(
d.bg, EVAS_CALLBACK_KEY_DOWN, _on_keydown, NULL);
d.logo = evas_object_image_filled_add(d.evas);
evas_object_image_file_set(d.logo, img_path, NULL);
evas_object_resize(d.logo, WIDTH / 2, HEIGHT);
evas_object_show(d.logo);
d.logo1 = evas_object_image_filled_add(d.evas);
evas_object_image_file_set(d.logo1, img_path, NULL);
evas_object_resize(d.logo1, WIDTH / 2, HEIGHT);
evas_object_move(d.logo1, WIDTH / 2, 0);
evas_object_show(d.logo1);
fprintf(stdout, commands);
ecore_main_loop_begin();
ecore_evas_free(d.ee);
ecore_evas_shutdown();
return 0;
error:
fprintf(stderr, "you got to have at least one evas engine built and linked"
" up to ecore-evas for this example to run properly.\n");
ecore_evas_shutdown();
return -1;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,932 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_common.h"
#include "evas_private.h"
#include "evas_cache2.h"
#include "evas_cs2.h"
#include "evas_cs2_private.h"
#define FREESTRC(Var) \
if (Var) \
{ \
eina_stringshare_del(Var); \
Var = NULL; \
}
static void _evas_cache_image_dirty_add(Image_Entry *im);
static void _evas_cache_image_dirty_del(Image_Entry *im);
static void _evas_cache_image_activ_add(Image_Entry *im);
static void _evas_cache_image_activ_del(Image_Entry *im);
static void _evas_cache_image_lru_add(Image_Entry *im);
static void _evas_cache_image_lru_del(Image_Entry *im);
static void _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target);
// static void _evas_cache_image_lru_nodata_add(Image_Entry *im);
// static void _evas_cache_image_lru_nodata_del(Image_Entry *im);
static void
_evas_cache_image_dirty_add(Image_Entry *im)
{
if (im->flags.dirty) return;
_evas_cache_image_activ_del(im);
_evas_cache_image_lru_del(im);
// _evas_cache_image_lru_nodata_del(im);
im->flags.dirty = 1;
im->flags.cached = 1;
im->cache2->dirty = eina_inlist_prepend(im->cache2->dirty, EINA_INLIST_GET(im));
if (im->cache_key)
{
eina_stringshare_del(im->cache_key);
im->cache_key = NULL;
}
}
static void
_evas_cache_image_dirty_del(Image_Entry *im)
{
if (!im->flags.dirty) return;
if (!im->cache2) return;
im->flags.dirty = 0;
im->flags.cached = 0;
im->cache2->dirty = eina_inlist_remove(im->cache2->dirty, EINA_INLIST_GET(im));
}
static void
_evas_cache_image_activ_add(Image_Entry *im)
{
if (im->flags.activ) return;
_evas_cache_image_dirty_del(im);
_evas_cache_image_lru_del(im);
// _evas_cache_image_lru_nodata_del(im);
if (!im->cache_key) return;
im->flags.activ = 1;
im->flags.cached = 1;
eina_hash_direct_add(im->cache2->activ, im->cache_key, im);
}
static void
_evas_cache_image_activ_del(Image_Entry *im)
{
if (!im->flags.activ) return;
if (!im->cache_key) return;
im->flags.activ = 0;
im->flags.cached = 0;
eina_hash_del(im->cache2->activ, im->cache_key, im);
}
static void
_evas_cache_image_lru_add(Image_Entry *im)
{
if (im->flags.lru) return;
_evas_cache_image_dirty_del(im);
_evas_cache_image_activ_del(im);
// _evas_cache_image_lru_nodata_del(im);
if (!im->cache_key) return;
im->flags.lru = 1;
im->flags.cached = 1;
eina_hash_direct_add(im->cache2->inactiv, im->cache_key, im);
im->cache2->lru = eina_inlist_prepend(im->cache2->lru, EINA_INLIST_GET(im));
im->cache2->usage += im->cache2->func.mem_size_get(im);
}
static void
_evas_cache_image_lru_del(Image_Entry *im)
{
if (!im->flags.lru) return;
if (!im->cache_key) return;
im->flags.lru = 0;
im->flags.cached = 0;
eina_hash_del(im->cache2->inactiv, im->cache_key, im);
im->cache2->lru = eina_inlist_remove(im->cache2->lru, EINA_INLIST_GET(im));
im->cache2->usage -= im->cache2->func.mem_size_get(im);
}
/*
static void
_evas_cache_image_lru_nodata_add(Image_Entry *im)
{
if (im->flags.lru_nodata) return;
_evas_cache_image_dirty_del(im);
_evas_cache_image_activ_del(im);
_evas_cache_image_lru_del(im);
im->flags.lru = 1;
im->flags.cached = 1;
im->cache2->lru_nodata = eina_inlist_prepend(im->cache2->lru_nodata, EINA_INLIST_GET(im));
}
static void
_evas_cache_image_lru_nodata_del(Image_Entry *im)
{
if (!im->flags.lru_nodata) return;
im->flags.lru = 0;
im->flags.cached = 0;
im->cache2->lru_nodata = eina_inlist_remove(im->cache2->lru_nodata, EINA_INLIST_GET(im));
}
*/
static Eina_Bool
_timestamp_compare(Image_Timestamp *tstamp, struct stat *st)
{
if (tstamp->mtime != st->st_mtime) return EINA_FALSE;
if (tstamp->size != st->st_size) return EINA_FALSE;
if (tstamp->ino != st->st_ino) return EINA_FALSE;
#ifdef _STAT_VER_LINUX
#if (defined __USE_MISC && defined st_mtime)
if (tstamp->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec)
return EINA_FALSE;
#else
if (tstamp->mtime_nsec != (unsigned long int)st->st_mtimensec)
return EINA_FALSE;
#endif
#endif
return EINA_TRUE;
}
static void
_timestamp_build(Image_Timestamp *tstamp, struct stat *st)
{
tstamp->mtime = st->st_mtime;
tstamp->size = st->st_size;
tstamp->ino = st->st_ino;
#ifdef _STAT_VER_LINUX
#if (defined __USE_MISC && defined st_mtime)
tstamp->mtime_nsec = (unsigned long int)st->st_mtim.tv_nsec;
#else
tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec;
#endif
#endif
}
static void
_evas_cache_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie)
{
if (!ie) return;
if (ie->flags.delete_me == 1)
return;
if (ie->preload_rid)
{
ie->flags.delete_me = 1;
_evas_cache2_image_entry_preload_remove(ie, NULL);
return;
}
_evas_cache_image_dirty_del(ie);
_evas_cache_image_activ_del(ie);
_evas_cache_image_lru_del(ie);
// _evas_cache_image_lru_nodata_del(ie);
if (ie->data1)
{
evas_cserve2_image_unload(ie);
evas_cache2_image_unload_data(ie);
evas_cserve2_image_free(ie);
}
else
{
if (cache)
cache->func.surface_delete(ie);
}
FREESTRC(ie->cache_key);
FREESTRC(ie->file);
FREESTRC(ie->key);
ie->cache2 = NULL;
evas_common_rgba_image_scalecache_shutdown(ie);
free(ie);
}
static Image_Entry *
_evas_cache_image_entry_new(Evas_Cache2 *cache,
const char *hkey,
Image_Timestamp *tstamp,
const char *file,
const char *key,
RGBA_Image_Loadopts *lo,
int *error)
{
Image_Entry *ie;
RGBA_Image *im;
// ie = cache->func.alloc();
im = calloc(1, sizeof(RGBA_Image));
if (!im)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return NULL;
}
im->flags = RGBA_IMAGE_NOTHING;
im->ref = 1;
evas_common_rgba_image_scalecache_init(&im->cache_entry);
ie = &im->cache_entry;
ie->cache2 = cache;
if (hkey) ie->cache_key = eina_stringshare_add(hkey);
ie->flags.need_data = 1;
ie->space = EVAS_COLORSPACE_ARGB8888;
ie->w = -1;
ie->h = -1;
ie->scale = 1;
if (file) ie->file = eina_stringshare_add(file);
if (key) ie->key = eina_stringshare_add(key);
if (tstamp) ie->tstamp = *tstamp;
else memset(&ie->tstamp, 0, sizeof(Image_Timestamp));
if (lo) ie->load_opts = *lo;
if (ie->file)
{
if (!evas_cserve2_image_load(ie, ie->file, ie->key, &(ie->load_opts)))
{
ERR("couldn't load '%s' '%s' with cserve2!",
ie->file, ie->key ? ie->key : "");
_evas_cache_image_entry_delete(cache, ie);
return NULL;
}
}
if (ie->cache_key) _evas_cache_image_activ_add(ie);
else _evas_cache_image_dirty_add(ie);
return ie;
}
EAPI void
evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h)
{
Evas_Cache2 *cache = ie->cache2;
int wmin = w > 0 ? w : 1;
int hmin = h > 0 ? h : 1;
if (cache->func.surface_alloc(ie, wmin, hmin))
{
wmin = 0;
hmin = 0;
}
ie->w = wmin;
ie->h = hmin;
ie->allocated.w = wmin;
ie->allocated.h = hmin;
ie->flags.loaded = EINA_TRUE;
}
static void
_evas_cache2_image_preloaded_cb(void *data, Eina_Bool success)
{
Image_Entry *ie = data;
Evas_Cache_Target *tmp;
ie->cache2->preload = eina_list_remove(ie->cache2->preload, ie);
ie->flags.preload_done = success;
while ((tmp = ie->targets))
{
ie->targets = (Evas_Cache_Target *)
eina_inlist_remove(EINA_INLIST_GET(ie->targets),
EINA_INLIST_GET(ie->targets));
if (!ie->flags.delete_me)
evas_object_inform_call_image_preloaded((Evas_Object *) tmp->target);
free(tmp);
}
if (ie->flags.delete_me)
_evas_cache_image_entry_delete(ie->cache2, ie);
}
static Eina_Bool
_evas_cache2_image_entry_preload_add(Image_Entry *ie, const void *target)
{
Evas_Cache_Target *tg;
if (ie->flags.preload_done)
return EINA_FALSE;
tg = malloc(sizeof(Evas_Cache_Target));
if (!tg)
return EINA_TRUE;
tg->target = target;
ie->targets = (Evas_Cache_Target *)
eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
if (!ie->preload_rid)
{
ie->cache2->preload = eina_list_append(ie->cache2->preload, ie);
evas_cserve2_image_preload(ie, _evas_cache2_image_preloaded_cb);
}
return EINA_TRUE;
}
static void
_evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target)
{
if (target)
{
Evas_Cache_Target *tg;
EINA_INLIST_FOREACH(ie->targets, tg)
{
if (tg->target == target)
{
ie->targets = (Evas_Cache_Target *)
eina_inlist_remove(EINA_INLIST_GET(ie->targets),
EINA_INLIST_GET(tg));
free(tg);
break;
}
}
}
else
{
Evas_Cache_Target *tg;
while (ie->targets)
{
tg = ie->targets;
ie->targets = (Evas_Cache_Target *)
eina_inlist_remove(EINA_INLIST_GET(ie->targets),
EINA_INLIST_GET(tg));
free(tg);
}
}
// FIXME: Should also send message to the server to cancel the request.
}
EAPI Image_Entry *
evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
{
Image_Entry *im;
if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
(cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
(cspace == EVAS_COLORSPACE_YCBCR422601_PL))
w &= ~0x1;
im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
if (!im)
return NULL;
im->space = cspace;
im->flags.alpha = alpha;
evas_cache2_image_surface_alloc(im, w, h);
if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
{
_evas_cache_image_entry_delete(cache, im);
return NULL;
}
im->references = 1;
im->flags.loaded = EINA_TRUE;
if (cache->func.debug) cache->func.debug("copied-data", im);
return im;
}
EAPI Image_Entry *
evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
{
Image_Entry *im;
if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
(cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
(cspace == EVAS_COLORSPACE_YCBCR422601_PL))
w &= ~0x1;
im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
if (!im) return NULL;
im->w = w;
im->h = h;
im->flags.alpha = alpha;
im->flags.loaded = 1;
if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
{
_evas_cache_image_entry_delete(cache, im);
return NULL;
}
im->references = 1;
if (cache->func.debug) cache->func.debug("data", im);
return im;
}
EAPI Image_Entry *
evas_cache2_image_empty(Evas_Cache2 *cache)
{
Image_Entry *im;
im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
if (!im)
return NULL;
im->references = 1;
return im;
}
EAPI Image_Entry *
evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h)
{
Evas_Cache2 *cache;
Image_Entry *im2 = NULL;
int error;
if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
(im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
(im->space == EVAS_COLORSPACE_YCBCR422601_PL))
w &= ~0x1;
if ((im->w == w) && (im->h == h)) return im;
cache = im->cache2;
im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL,
NULL);
if (!im2) goto on_error;
im2->flags.alpha = im->flags.alpha;
im2->space = im->space;
im2->load_opts = im->load_opts;
evas_cache2_image_surface_alloc(im2, w, h);
error = cache->func.size_set(im2, im, w, h);
if (error != 0) goto on_error;
im2->references = 1;
evas_cache2_image_close(im);
return im2;
on_error:
if (im2)
_evas_cache_image_entry_delete(cache, im2);
return NULL;
}
EAPI Evas_Cache2 *
evas_cache2_init(const Evas_Cache2_Image_Func *cb)
{
Evas_Cache2 *cache = calloc(1, sizeof(Evas_Cache2));
cache->func = *cb;
cache->activ = eina_hash_string_superfast_new(NULL);
cache->inactiv = eina_hash_string_superfast_new(NULL);
return cache;
}
EAPI void
evas_cache2_shutdown(Evas_Cache2 *cache)
{
eina_hash_free(cache->activ);
eina_hash_free(cache->inactiv);
free(cache);
}
static void
_create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, RGBA_Image_Loadopts *lo)
{
const char *ckey = "(null)";
size_t size;
/* generate hkey from file+key+load opts */
memcpy(hkey, path, pathlen);
size = pathlen;
memcpy(hkey + size, "//://", 5);
size += 5;
if (key) ckey = key;
memcpy(hkey + size, ckey, keylen);
size += keylen;
if (lo)
{
memcpy(hkey + size, "//@/", 4);
size += 4;
size += eina_convert_xtoa(lo->scale_down_by, hkey + size);
hkey[size] = '/';
size += 1;
size += eina_convert_dtoa(lo->dpi, hkey + size);
hkey[size] = '/';
size += 1;
size += eina_convert_xtoa(lo->w, hkey + size);
hkey[size] = 'x';
size += 1;
size += eina_convert_xtoa(lo->h, hkey + size);
hkey[size] = '/';
size += 1;
size += eina_convert_xtoa(lo->region.x, hkey + size);
hkey[size] = '+';
size += 1;
size += eina_convert_xtoa(lo->region.y, hkey + size);
hkey[size] = '.';
size += 1;
size += eina_convert_xtoa(lo->region.w, hkey + size);
hkey[size] = 'x';
size += 1;
size += eina_convert_xtoa(lo->region.h, hkey + size);
if (lo->orientation)
{
hkey[size] = '/';
size += 1;
hkey[size] = 'o';
size += 1;
}
}
hkey[size] = '\0';
}
EAPI Image_Entry *
evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, RGBA_Image_Loadopts *lo, int *error)
{
size_t size;
size_t pathlen;
size_t keylen;
char *hkey;
Image_Entry *im;
int stat_done = 0, stat_failed = 0;
struct stat st;
Image_Timestamp tstamp;
Evas_Image_Load_Opts prevent = { 0, 0.0, 0, 0, 0, { 0, 0, 0, 0 }, EINA_FALSE };
if ((!path) || ((!path) && (!key)))
{
*error = EVAS_LOAD_ERROR_GENERIC;
return NULL;
}
pathlen = strlen(path);
keylen = key ? strlen(key) : 6;
size = pathlen + keylen + 132;
hkey = alloca(sizeof(char) * size);
_create_hash_key(hkey, path, pathlen, key, keylen, lo);
DBG("Looking at the hash for key '%s'", hkey);
/* use local var to copy default load options to the image entry */
if ((!lo) ||
(lo &&
(lo->scale_down_by == 0) &&
(lo->dpi == 0.0) &&
((lo->w == 0) || (lo->h == 0)) &&
((lo->region.w == 0) || (lo->region.h == 0)) &&
(lo->orientation == 0)
))
{
lo = &prevent;
}
im = eina_hash_find(cache->activ, hkey);
if (im)
{
int ok = 1;
DBG("Found entry on active hash for key: '%s'", hkey);
stat_done = 1;
if (stat(path, &st) < 0)
{
stat_failed = 1;
ok = 0;
}
else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
if (ok) goto on_ok;
/* image we found doesn't match what's on disk (stat info wise)
* so dirty the active cache entry so we never find it again. this
* also implicitly guarantees that we only have 1 active copy
* of an image at a given key. we wither find it and keep re-reffing
* it or we dirty it and get it out */
DBG("Entry on inactive hash was invalid (file changed or deleted).");
_evas_cache_image_dirty_add(im);
im = NULL;
}
im = eina_hash_find(cache->inactiv, hkey);
if (im)
{
int ok = 1;
DBG("Found entry on inactive hash for key: '%s'", hkey);
if (!stat_done)
{
stat_done = 1;
if (stat(path, &st) < 0)
{
stat_failed = 1;
ok = 0;
}
else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
}
else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
if (ok)
{
/* remove from lru and make it active again */
_evas_cache_image_lru_del(im);
_evas_cache_image_activ_add(im);
goto on_ok;
}
DBG("Entry on inactive hash was invalid (file changed or deleted).");
/* as avtive cache find - if we match in lru and its invalid, dirty */
_evas_cache_image_dirty_add(im);
/* this image never used, so it have to be deleted */
_evas_cache_image_entry_delete(cache, im);
im = NULL;
}
if (stat_failed) goto on_stat_error;
if (!stat_done)
{
if (stat(path, &st) < 0) goto on_stat_error;
}
_timestamp_build(&tstamp, &st);
DBG("Creating a new entry for key '%s'.", hkey);
im = _evas_cache_image_entry_new(cache, hkey, &tstamp, path, key,
lo, error);
if (!im) goto on_stat_error;
on_ok:
*error = EVAS_LOAD_ERROR_NONE;
DBG("Using entry on hash for key '%s'", hkey);
im->references++;
return im;
on_stat_error:
#ifndef _WIN32
if ((errno == ENOENT) || (errno == ENOTDIR) ||
(errno == ENAMETOOLONG) || (errno == ELOOP))
#else
if (errno == ENOENT)
#endif
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
#ifndef _WIN32
else if ((errno == ENOMEM) || (errno == EOVERFLOW))
#else
else if (errno == ENOMEM)
#endif
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
else if (errno == EACCES)
*error = EVAS_LOAD_ERROR_PERMISSION_DENIED;
else
*error = EVAS_LOAD_ERROR_GENERIC;
if (im) _evas_cache_image_entry_delete(cache, im);
return NULL;
}
EAPI int
evas_cache2_image_open_wait(Image_Entry *im)
{
DBG("Wait for open image '%s' '%s'", im->file, im->key);
if (evas_cserve2_image_load_wait(im) != CSERVE2_NONE)
return EVAS_LOAD_ERROR_GENERIC;
return EVAS_LOAD_ERROR_NONE;
}
EAPI void
evas_cache2_image_close(Image_Entry *im)
{
Evas_Cache2 *cache;
int references;
im->references--;
if (im->references < 0)
{
ERR("image with negative references: %d", im->references);
im->references = 0;
}
references = im->references;
cache = im->cache2;
if (references > 0)
return;
if (im->flags.dirty)
{
_evas_cache_image_entry_delete(cache, im);
return;
}
_evas_cache_image_lru_add(im);
if (cache)
evas_cache2_flush(cache);
}
EAPI int
evas_cache2_image_load_data(Image_Entry *ie)
{
int error = EVAS_LOAD_ERROR_NONE;
if ((ie->flags.loaded) && (!ie->flags.animated))
return error;
ie->flags.in_progress = EINA_TRUE;
DBG("try cserve2 image data '%s' '%s'",
ie->file, ie->key ? ie->key : "");
if (evas_cserve2_image_data_load(ie))
{
evas_cserve2_image_load_data_wait(ie);
RGBA_Image *im = (RGBA_Image *)ie;
im->image.data = evas_cserve2_image_data_get(ie);
DBG("try cserve2 image data '%s' '%s' loaded!",
ie->file, ie->key ? ie->key : "");
if (im->image.data)
{
im->image.no_free = 1;
error = EVAS_LOAD_ERROR_NONE;
}
else
{
ERR("Failed to load data for image '%s' '%s'.",
ie->file, ie->key ? ie->key : "");
error = EVAS_LOAD_ERROR_GENERIC;
}
}
else
{
ERR("Couldn't send LOAD message to cserve2.");
error = EVAS_LOAD_ERROR_GENERIC;
}
ie->flags.in_progress = EINA_FALSE;
ie->flags.loaded = 1;
if (error != EVAS_LOAD_ERROR_NONE)
ie->flags.loaded = 0;
return error;
}
EAPI void
evas_cache2_image_unload_data(Image_Entry *im)
{
// FIXME: This function seems pretty useless, since we always have
// to send an UNLOAD message to the server when closing an image,
// even if we didn't send a LOAD message before, because the SETOPTS
// message increases the image refcount.
if (im->flags.in_progress)
return;
if ((!im->file))
return;
if (!im->flags.loaded)
return;
// if (im->data2)
im->flags.loaded = 0;
}
EAPI void
evas_cache2_image_preload_data(Image_Entry *im, const void *target)
{
RGBA_Image *img = (RGBA_Image *)im;
if ((im->flags.loaded) && (img->image.data))
{
evas_object_inform_call_image_preloaded((Evas_Object *)target);
return;
}
if (!_evas_cache2_image_entry_preload_add(im, target))
evas_object_inform_call_image_preloaded((Evas_Object *)target);
}
EAPI void
evas_cache2_image_preload_cancel(Image_Entry *im, const void *target)
{
if (!target)
return;
_evas_cache2_image_entry_preload_remove(im, target);
}
EAPI DATA32 *
evas_cache2_image_pixels(Image_Entry *im)
{
return im->cache2->func.surface_pixels(im);
}
EAPI Image_Entry *
evas_cache2_image_writable(Image_Entry *im)
{
Evas_Cache2 *cache = im->cache2;
Image_Entry *im2 = NULL;
if (!im->cache_key)
{
if (!im->flags.dirty)
_evas_cache_image_dirty_add(im);
return im;
}
im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
evas_cache2_image_pixels(im),
im->flags.alpha, im->space);
if (!im2)
goto on_error;
evas_cache2_image_close(im);
return im2;
on_error:
if (im2)
_evas_cache_image_entry_delete(cache, im2);
return NULL;
}
EAPI Image_Entry *
evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{
Evas_Cache2 *cache = im->cache2;
Image_Entry *im2 = NULL;
if (!im->cache_key)
{
if (!im->flags.dirty)
_evas_cache_image_dirty_add(im);
im2 = im;
}
else
{
im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
evas_cache2_image_pixels(im),
im->flags.alpha, im->space);
if (!im2)
goto on_error;
evas_cache2_image_close(im);
}
if (cache->func.dirty_region)
cache->func.dirty_region(im2, x, y, w, h);
return im2;
on_error:
if (im2)
_evas_cache_image_entry_delete(cache, im2);
evas_cache2_image_close(im);
return NULL;
}
EAPI int
evas_cache2_flush(Evas_Cache2 *cache)
{
if (cache->limit == -1) return -1;
while ((cache->lru) && (cache->limit < cache->usage))
{
Image_Entry *im;
im = (Image_Entry *)cache->lru->last;
DBG("Remove unused entry from cache.");
_evas_cache_image_entry_delete(cache, im);
}
return cache->usage;
}
EAPI void
evas_cache2_limit_set(Evas_Cache2 *cache, int limit)
{
if (cache->limit == limit)
return;
DBG("Cache2 limit set to %d", limit);
cache->limit = limit;
evas_cache2_flush(cache);
}
EAPI int
evas_cache2_limit_get(Evas_Cache2 *cache)
{
return cache->limit;
}
EAPI int
evas_cache2_usage_get(Evas_Cache2 *cache)
{
return cache->usage;
}

View File

@ -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 */

View File

@ -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)\" \

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -0,0 +1,133 @@
#ifndef EVAS_CS2_H
#define EVAS_CS2_H 1
#include <Eina.h>
#ifdef EVAS_CSERVE2
typedef enum {
CSERVE2_OPEN = 1,
CSERVE2_OPENED,
CSERVE2_SETOPTS,
CSERVE2_SETOPTSED,
CSERVE2_LOAD,
CSERVE2_LOADED,
CSERVE2_PRELOAD,
CSERVE2_PRELOADED,
CSERVE2_UNLOAD,
CSERVE2_CLOSE,
CSERVE2_ERROR
} Message_Type;
typedef enum {
CSERVE2_NONE,
CSERVE2_GENERIC,
CSERVE2_DOES_NOT_EXIST,
CSERVE2_PERMISSION_DENIED,
CSERVE2_RESOURCE_ALLOCATION_FAILED,
CSERVE2_CORRUPT_FILE,
CSERVE2_UNKNOWN_FORMAT,
CSERVE2_INVALID_COMMAND,
CSERVE2_LOADER_DIED,
CSERVE2_LOADER_EXEC_ERR,
CSERVE2_INVALID_CACHE, // invalid cserve cache entry
CSERVE2_FILE_CHANGED,
CSERVE2_REQUEST_CANCEL
} Error_Type;
struct _Msg_Base {
int type;
unsigned int rid;
};
typedef struct _Msg_Base Msg_Base;
struct _Msg_Open {
Msg_Base base;
unsigned int file_id;
int path_offset;
int key_offset;
};
struct _Msg_Opened {
Msg_Base base;
struct {
int w, h;
int frame_count;
int loop_count;
int loop_hint; /* include Evas.h? Copy the enum around? */
Eina_Bool alpha : 1;
} image;
};
struct _Msg_Setopts {
Msg_Base base;
unsigned int file_id;
unsigned int image_id;
struct {
double dpi;
int w, h;
int scale_down;
int rx, ry, rw, rh;
Eina_Bool orientation;
} opts;
};
struct _Msg_Setoptsed {
Msg_Base base;
};
struct _Msg_Load {
Msg_Base base;
unsigned int image_id;
};
struct _Msg_Loaded {
Msg_Base base;
struct {
int mmap_offset;
int use_offset;
int mmap_size;
int image_size;
} shm;
Eina_Bool alpha_sparse : 1;
};
struct _Msg_Preload {
Msg_Base base;
unsigned int image_id;
};
struct _Msg_Preloaded {
Msg_Base base;
};
struct _Msg_Unload {
Msg_Base base;
unsigned int image_id;
};
struct _Msg_Close {
Msg_Base base;
unsigned int file_id;
};
struct _Msg_Error {
Msg_Base base;
int error;
};
typedef struct _Msg_Open Msg_Open;
typedef struct _Msg_Opened Msg_Opened;
typedef struct _Msg_Setopts Msg_Setopts;
typedef struct _Msg_Setoptsed Msg_Setoptsed;
typedef struct _Msg_Load Msg_Load;
typedef struct _Msg_Loaded Msg_Loaded;
typedef struct _Msg_Preload Msg_Preload;
typedef struct _Msg_Preloaded Msg_Preloaded;
typedef struct _Msg_Unload Msg_Unload;
typedef struct _Msg_Close Msg_Close;
typedef struct _Msg_Error Msg_Error;
#endif
#endif

View File

@ -0,0 +1,742 @@
#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <Eina.h>
#include "evas_cs2.h"
#include "evas_cs2_private.h"
#ifdef EVAS_CSERVE2
typedef void (*Op_Callback)(void *data, const void *msg);
struct _File_Entry {
unsigned int file_id;
};
struct _Client_Request {
Message_Type type;
unsigned int rid;
Op_Callback cb;
void *data;
};
typedef struct _File_Entry File_Entry;
typedef struct _Client_Request Client_Request;
static int cserve2_init = 0;
static int socketfd = -1;
static unsigned int _rid_count = 0;
static unsigned int _file_id = 0;
static unsigned int _data_id = 0;
static Eina_List *_requests = NULL;
static struct sockaddr_un socksize;
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX sizeof(socksize.sun_path)
#endif
static void
_socket_path_set(char *path)
{
char *env;
char buf[UNIX_PATH_MAX];
env = getenv("EVAS_CSERVE2_SOCKET");
if (env && env[0])
{
strncpy(path, env, UNIX_PATH_MAX - 1);
return;
}
env = getenv("XDG_RUNTIME_DIR");
if (!env || !env[0])
{
env = getenv("HOME");
if (!env || !env[0])
{
env = getenv("TMPDIR");
if (!env || !env[0])
env = "/tmp";
}
}
snprintf(buf, sizeof(buf), "%s/evas-cserve2-%x.socket", env, getuid());
/* FIXME: check we can actually create this socket */
strcpy(path, buf);
}
static Eina_Bool
_server_connect(void)
{
int s, len;
struct sockaddr_un remote;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
ERR("socket");
return EINA_FALSE;
}
remote.sun_family = AF_UNIX;
_socket_path_set(remote.sun_path);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *)&remote, len) == -1)
{
ERR("connect");
return EINA_FALSE;
}
fcntl(s, F_SETFL, O_NONBLOCK);
socketfd = s;
DBG("connected to cserve2 server.");
return EINA_TRUE;
}
static void
_server_disconnect(void)
{
close(socketfd);
socketfd = -1;
}
static void
_request_answer_add(Message_Type type, unsigned int rid, Op_Callback cb, void *data)
{
Client_Request *cr = calloc(1, sizeof(*cr));
cr->type = type;
cr->rid = rid;
cr->cb = cb;
cr->data = data;
_requests = eina_list_append(_requests, cr);
}
static Eina_Bool
_server_send(const void *buf, int size, Op_Callback cb, void *data)
{
const Msg_Base *msg;
if (send(socketfd, &size, sizeof(size), MSG_NOSIGNAL) == -1)
{
ERR("Couldn't send message size to server.");
return EINA_FALSE;
}
if (send(socketfd, buf, size, MSG_NOSIGNAL) == -1)
{
ERR("Couldn't send message body to server.");
return EINA_FALSE;
}
msg = buf;
switch (msg->type)
{
case CSERVE2_OPEN:
case CSERVE2_SETOPTS:
case CSERVE2_LOAD:
case CSERVE2_PRELOAD:
_request_answer_add(msg->type, msg->rid, cb, data);
break;
default:
break;
}
return EINA_TRUE;
}
static int sr_size = 0;
static int sr_got = 0;
static char *sr_buf = NULL;
static void *
_server_read(int *size)
{
int n;
void *ret;
if (sr_size)
goto get_data;
n = recv(socketfd, &sr_size, sizeof(sr_size), 0);
if (n < 0)
return NULL;
sr_buf = malloc(sr_size);
get_data:
n = recv(socketfd, sr_buf + sr_got, sr_size - sr_got, 0);
if (n < 0)
return NULL;
sr_got += n;
if (sr_got < sr_size)
return NULL;
*size = sr_size;
sr_size = 0;
sr_got = 0;
ret = sr_buf;
sr_buf = NULL;
return ret;
}
int
evas_cserve2_init(void)
{
if (cserve2_init++)
return cserve2_init;
DBG("Connecting to cserve2.");
if (!_server_connect())
{
cserve2_init = 0;
return 0;
}
return cserve2_init;
}
int
evas_cserve2_shutdown(void)
{
if ((--cserve2_init) > 0)
return cserve2_init;
DBG("Disconnecting from cserve2.");
_server_disconnect();
return cserve2_init;
}
int
evas_cserve2_use_get(void)
{
return cserve2_init;
}
static unsigned int
_next_rid(void)
{
if (!_rid_count)
_rid_count++;
return _rid_count++;
}
static unsigned int
_server_dispatch(void)
{
int size;
unsigned int rid;
Eina_List *l, *l_next;
Client_Request *cr;
Msg_Base *msg;
msg = _server_read(&size);
if (!msg)
return 0;
EINA_LIST_FOREACH_SAFE(_requests, l, l_next, cr)
{
if (cr->rid != msg->rid) // dispatch this answer
continue;
_requests = eina_list_remove_list(_requests, l);
if (cr->cb)
cr->cb(cr->data, msg);
free(cr);
}
rid = msg->rid;
free(msg);
return rid;
}
static void
_server_dispatch_until(unsigned int rid)
{
Eina_Bool done = EINA_FALSE;
while (!done)
{
if (_server_dispatch() == rid)
done = EINA_TRUE;
}
}
static void
_image_opened_cb(void *data, const void *msg_received)
{
const Msg_Base *answer = msg_received;
const Msg_Opened *msg = msg_received;
Image_Entry *ie = data;
ie->open_rid = 0;
if (answer->type == CSERVE2_ERROR)
{
const Msg_Error *msg_error = msg_received;
ERR("Couldn't open image: '%s':'%s'; error: %d",
ie->file, ie->key, msg_error->error);
free(ie->data1);
ie->data1 = NULL;
return;
}
ie->w = msg->image.w;
ie->h = msg->image.h;
ie->flags.alpha = msg->image.alpha;
ie->loop_hint = msg->image.loop_hint;
ie->loop_count = msg->image.loop_count;
ie->frame_count = msg->image.frame_count;
}
static void
_image_loaded_cb(void *data, const void *msg_received)
{
const Msg_Base *answer = msg_received;
const Msg_Loaded *msg = msg_received;
Image_Entry *ie = data;
Data_Entry *dentry = ie->data2;
const char *shmpath;
int fd;
ie->load_rid = 0;
if (!ie->data2)
return;
if (answer->type == CSERVE2_ERROR)
{
const Msg_Error *msg_error = msg_received;
ERR("Couldn't load image: '%s':'%s'; error: %d",
ie->file, ie->key, msg_error->error);
free(ie->data2);
ie->data2 = NULL;
return;
}
shmpath = ((const char *)msg) + sizeof(*msg);
// dentry->shm.path = strdup(shmpath);
dentry->shm.mmap_offset = msg->shm.mmap_offset;
dentry->shm.use_offset = msg->shm.use_offset;
dentry->shm.mmap_size = msg->shm.mmap_size;
dentry->shm.image_size = msg->shm.image_size;
fd = shm_open(shmpath, O_RDONLY, S_IRUSR);
if (fd < 0)
{
free(dentry);
ie->data2 = NULL;
return;
}
dentry->shm.data = mmap(NULL, dentry->shm.mmap_size, PROT_READ,
MAP_SHARED, fd, dentry->shm.mmap_offset);
if (dentry->shm.data == MAP_FAILED)
{
free(dentry);
ie->data2 = NULL;
}
close(fd);
if (ie->data2)
{
ie->flags.loaded = EINA_TRUE;
ie->flags.alpha_sparse = msg->alpha_sparse;
}
}
static void
_image_preloaded_cb(void *data, const void *msg_received)
{
const Msg_Base *answer = msg_received;
const Msg_Opened *msg = msg_received;
Image_Entry *ie = data;
Data_Entry *dentry = ie->data2;
DBG("Received PRELOADED for RID: %d", answer->rid);
ie->preload_rid = 0;
if (answer->type == CSERVE2_ERROR)
{
const Msg_Error *msg_error = msg_received;
ERR("Couldn't preload image: '%s':'%s'; error: %d",
ie->file, ie->key, msg_error->error);
dentry->preloaded_cb(data, EINA_FALSE);
dentry->preloaded_cb = NULL;
return;
}
if (dentry && (dentry->preloaded_cb))
{
dentry->preloaded_cb(data, EINA_TRUE);
dentry->preloaded_cb = NULL;
}
}
static const char *
_build_absolute_path(const char *path, char buf[], int size)
{
char *p;
int len;
if (!path)
return NULL;
p = buf;
if (path[0] == '/')
strncpy(p, path, size);
else if (path[0] == '~')
{
const char *home = getenv("HOME");
if (!home)
return NULL;
strncpy(p, home, size);
len = strlen(p);
size -= len + 1;
p += len;
p[0] = '/';
p++;
strncpy(p, path + 2, size);
}
else
{
if (!getcwd(p, size))
return NULL;
len = strlen(p);
size -= len + 1;
p += len;
p[0] = '/';
p++;
strncpy(p, path, size);
}
return buf;
}
static unsigned int
_image_open_server_send(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
{
int flen, klen;
int size;
char *buf;
char filebuf[PATH_MAX];
Msg_Open msg_open;
File_Entry *fentry;
if (cserve2_init == 0)
{
ERR("Server not initialized.");
return 0;
}
if (!key) key = "";
_build_absolute_path(file, filebuf, sizeof(filebuf));
fentry = calloc(1, sizeof(*fentry));
memset(&msg_open, 0, sizeof(msg_open));
fentry->file_id = ++_file_id;
if (fentry->file_id == 0)
fentry->file_id = ++_file_id;
flen = strlen(filebuf) + 1;
klen = strlen(key) + 1;
msg_open.base.rid = _next_rid();
msg_open.base.type = CSERVE2_OPEN;
msg_open.file_id = fentry->file_id;
msg_open.path_offset = 0;
msg_open.key_offset = flen;
size = sizeof(msg_open) + flen + klen;
buf = malloc(size);
if (!buf) return EINA_FALSE;
memcpy(buf, &msg_open, sizeof(msg_open));
memcpy(buf + sizeof(msg_open), filebuf, flen);
memcpy(buf + sizeof(msg_open) + flen, key, klen);
if (!_server_send(buf, size, _image_opened_cb, ie))
{
ERR("Couldn't send message to server.");
free(buf);
return 0;
}
free(buf);
ie->data1 = fentry;
return msg_open.base.rid;
}
unsigned int
_image_setopts_server_send(Image_Entry *ie)
{
File_Entry *fentry;
Data_Entry *dentry;
Msg_Setopts msg;
if (cserve2_init == 0)
return 0;
fentry = ie->data1;
dentry = calloc(1, sizeof(*dentry));
memset(&msg, 0, sizeof(msg));
dentry->image_id = ++_data_id;
if (dentry->image_id == 0)
dentry->image_id = ++_data_id;
msg.base.rid = _next_rid();
msg.base.type = CSERVE2_SETOPTS;
msg.file_id = fentry->file_id;
msg.image_id = dentry->image_id;
if (!_server_send(&msg, sizeof(msg), 0, NULL))
return 0;
ie->data2 = dentry;
return msg.base.rid;
}
unsigned int
_image_load_server_send(Image_Entry *ie)
{
Data_Entry *dentry;
Msg_Load msg;
if (cserve2_init == 0)
return 0;
if (!ie->data1)
{
ERR("No data for opened file.");
return 0;
}
dentry = ie->data2;
memset(&msg, 0, sizeof(msg));
msg.base.rid = _next_rid();
msg.base.type = CSERVE2_LOAD;
msg.image_id = dentry->image_id;
if (!_server_send(&msg, sizeof(msg), _image_loaded_cb, ie))
return 0;
return msg.base.rid;
}
unsigned int
_image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
{
Data_Entry *dentry;
Msg_Preload msg;
if (cserve2_init == 0)
return 0;
dentry = ie->data2;
dentry->preloaded_cb = preloaded_cb;
memset(&msg, 0, sizeof(msg));
msg.base.rid = _next_rid();
msg.base.type = CSERVE2_PRELOAD;
msg.image_id = dentry->image_id;
if (!_server_send(&msg, sizeof(msg), _image_preloaded_cb, ie))
return 0;
return msg.base.rid;
}
unsigned int
_image_close_server_send(Image_Entry *ie)
{
Msg_Close msg;
File_Entry *fentry;
if (cserve2_init == 0)
return 0;
if (!ie->data1)
return 0;
fentry = ie->data1;
if (ie->data2)
{
free(ie->data2);
ie->data2 = NULL;
}
memset(&msg, 0, sizeof(msg));
msg.base.rid = _next_rid();
msg.base.type = CSERVE2_CLOSE;
msg.file_id = fentry->file_id;
free(fentry);
ie->data1 = NULL;
if (!_server_send(&msg, sizeof(msg), NULL, NULL))
return 0;
return msg.base.rid;
}
unsigned int
_image_unload_server_send(Image_Entry *ie)
{
Msg_Unload msg;
Data_Entry *dentry;
if (cserve2_init == 0)
return 0;
if (!ie->data2)
return 0;
dentry = ie->data2;
// if (dentry->shm.path)
// free(dentry->shm.path);
memset(&msg, 0, sizeof(msg));
msg.base.rid = _next_rid();
msg.base.type = CSERVE2_UNLOAD;
msg.image_id = dentry->image_id;
free(dentry);
ie->data2 = NULL;
if (!_server_send(&msg, sizeof(msg), NULL, NULL))
return 0;
return msg.base.rid;
}
Eina_Bool
evas_cserve2_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
{
unsigned int rid;
rid = _image_open_server_send(ie, file, key, lopt);
if (!rid)
return EINA_FALSE;
ie->open_rid = rid;
_image_setopts_server_send(ie);
// _server_dispatch_until(rid);
if (ie->data1)
return EINA_TRUE;
else
return EINA_FALSE;
}
int
evas_cserve2_image_load_wait(Image_Entry *ie)
{
if (ie->open_rid)
{
_server_dispatch_until(ie->open_rid);
if (!ie->data1)
return CSERVE2_GENERIC;
return CSERVE2_NONE;
}
else
return CSERVE2_GENERIC;
}
Eina_Bool
evas_cserve2_image_data_load(Image_Entry *ie)
{
unsigned int rid;
rid = _image_load_server_send(ie);
if (!rid)
return EINA_FALSE;
ie->load_rid = rid;
if (ie->data2)
return EINA_TRUE;
else
return EINA_FALSE;
}
void
evas_cserve2_image_load_data_wait(Image_Entry *ie)
{
if (ie->load_rid)
_server_dispatch_until(ie->load_rid);
}
Eina_Bool
evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
{
unsigned int rid;
if (!ie->data1)
return EINA_FALSE;
rid = _image_preload_server_send(ie, preloaded_cb);
if (!rid)
return EINA_FALSE;
ie->preload_rid = rid;
return EINA_FALSE;
}
void
evas_cserve2_image_free(Image_Entry *ie)
{
if (!ie->data1)
return;
if (!_image_close_server_send(ie))
WRN("Couldn't send close message to cserve2.");
}
void
evas_cserve2_image_unload(Image_Entry *ie)
{
if (!ie->data2)
return;
if (!_image_unload_server_send(ie))
WRN("Couldn't send unload message to cserve2.");
}
void
evas_cserve2_dispatch(void)
{
_server_dispatch_until(0);
}
#endif

View File

@ -0,0 +1,23 @@
#include "config.h"
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "evas_cs2.h"
#include "evas_cs2_private.h"
#ifdef EVAS_CSERVE2
void *
evas_cserve2_image_data_get(Image_Entry *ie)
{
Data_Entry *dentry = ie->data2;
if (!dentry)
return NULL;
return dentry->shm.data;
}
#endif

View File

@ -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

View File

@ -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)\" \

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -8,6 +8,9 @@
#include <assert.h>
#ifdef EVAS_CSERVE2
#include "evas_cs2_private.h"
#endif
#include "evas_common.h"
#include "evas_private.h"
#include "evas_image_private.h"
@ -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)
{

View File

@ -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;

View File

@ -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@ \

View File

@ -1,3 +1,11 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef EVAS_CSERVE2
#include "evas_cs2_private.h"
#endif
#include "evas_common.h"
#include "evas_engine.h"
@ -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);
}
}
}
}

View File

@ -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@ \

View File

@ -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 <dlfcn.h> /* 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);
}

View File

@ -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@ \

View File

@ -5,6 +5,9 @@
#include <sys/time.h>
#include <sys/utsname.h>
#ifdef EVAS_CSERVE2
#include "evas_cs2_private.h"
#endif
#include "evas_common.h"
#include "evas_macros.h"
#include "evas_xlib_outbuf.h"
@ -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);