src/bin/evas_cserve_tool
src/bin/evas_cserve2
src/bin/evas_cserve2_slave
+src/bin/evas_cserve2_debug
src/bin/evas_cserve2_client
+src/bin/evas_cserve2_usage
src/bin/dummy_slave
*.gcno
*.gcov
evas-software-8-x11.pc.in \
evas-software-gdi.pc.in \
evas-software-ddraw.pc.in \
-evas-software-16-ddraw.pc.in \
evas-direct3d.pc.in \
evas-software-16-wince.pc.in \
evas-psl1ght.pc.in \
pkgconfig_DATA += evas-software-ddraw.pc
endif
-if BUILD_ENGINE_SOFTWARE_16_DDRAW
-pkgconfig_DATA += evas-software-16-ddraw.pc
-endif
-
if BUILD_ENGINE_DIRECT3D
pkgconfig_DATA += evas-direct3d.pc
endif
want_evas_engine_software_ddraw="no"
want_evas_engine_software_8_x11="no"
want_evas_engine_software_16_x11="no"
-want_evas_engine_software_16_ddraw="no"
want_evas_engine_software_16_wince="no"
want_evas_engine_software_16_sdl="no"
want_evas_engine_gl_xlib="no"
want_evas_engine_software_gdi="yes"
want_evas_engine_software_ddraw="yes"
want_evas_engine_direct3d="yes"
- want_evas_engine_software_16_ddraw="yes"
want_evas_image_loader_edb="no"
want_evas_image_loader_svg="no"
;;
if test "x${want_harfbuzz}" = "xyes" -o "x${want_harfbuzz}" = "xauto" ; then
PKG_CHECK_MODULES([HARFBUZZ],
- [harfbuzz >= 0.6.0],
+ [harfbuzz >= 0.9.0],
[
have_harfbuzz="yes"
requirement_evas="harfbuzz ${requirement_evas}"
EVAS_CHECK_ENGINE([software-16-x11], [${want_evas_engine_software_16_x11}], [no], [Software X11 16 bits])
-EVAS_CHECK_ENGINE([software-16-ddraw], [${want_evas_engine_software_16_ddraw}], [no], [Software DirectDraw 16 bits])
-
EVAS_CHECK_ENGINE([software-16-wince], [${want_evas_engine_software_16_wince}], [no], [Software Windows CE 16 bits])
EVAS_CHECK_ENGINE([software-16-sdl], [${want_evas_engine_software_16_sdl}], [no], [Software SDL 16 bits])
if test "x$have_evas_engine_software_16_sdl" = "xyes" -o "x$have_evas_engine_software_16_sdl" = "xstatic"; then
have_evas_engine_software_16="yes"
fi
-if test "x$have_evas_engine_software_16_ddraw" = "xyes" -o "x$have_evas_engine_software_16_ddraw" = "xstatic"; then
- have_evas_engine_software_16="yes"
-fi
if test "x$have_evas_engine_software_16_wince" = "xyes" -o "x$have_evas_engine_software_16_wince" = "xstatic"; then
have_evas_engine_software_16="yes"
fi
evas-software-16-x11.pc
evas-software-gdi.pc
evas-software-ddraw.pc
-evas-software-16-ddraw.pc
evas-direct3d.pc
evas-software-16-wince.pc
evas-software-sdl.pc
src/modules/engines/software_8_x11/Makefile
src/modules/engines/software_16/Makefile
src/modules/engines/software_16_x11/Makefile
-src/modules/engines/software_16_ddraw/Makefile
src/modules/engines/software_16_sdl/Makefile
src/modules/engines/wayland_shm/Makefile
src/modules/engines/wayland_egl/Makefile
# FIXME: kill software 16bit
echo " Software 16bit ............: $have_evas_engine_software_16"
echo " Software 16bit X11.........: $have_evas_engine_software_16_x11"
-echo " Software 16bit Directdraw..: $have_evas_engine_software_16_ddraw"
echo " Software 16bit WinCE.......: $have_evas_engine_software_16_wince"
echo " Software 16bit SDL.........: $have_evas_engine_software_16_sdl (primitive: $sdl_primitive)"
echo " Wayland Shm................: $have_evas_engine_wayland_shm"
+++ /dev/null
-Name: evas-software-16-ddraw
-Description: Evas 16bit software DirectDaw engine
-Version: @VERSION@
])
-dnl use: EVAS_CHECK_ENGINE_DEP_SOFTWARE_16_DDRAW(engine, simple, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
-
-AC_DEFUN([EVAS_CHECK_ENGINE_DEP_SOFTWARE_16_DDRAW],
-[
-
-have_dep="no"
-evas_engine_[]$1[]_cflags=""
-evas_engine_[]$1[]_libs=""
-
-AC_CHECK_HEADER([ddraw.h],
- [
- have_dep="yes"
- evas_engine_[]$1[]_libs="-lddraw -lgdi32"
- ]
-)
-
-AC_SUBST([evas_engine_$1_cflags])
-AC_SUBST([evas_engine_$1_libs])
-
-if test "x${have_dep}" = "xyes" ; then
- m4_default([$4], [:])
-else
- m4_default([$5], [:])
-fi
-
-])
-
dnl use: EVAS_CHECK_ENGINE_DEP_SOFTWARE_16_WINCE(engine, simple, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
AC_DEFUN([EVAS_CHECK_ENGINE_DEP_SOFTWARE_16_WINCE],
#sbs-git:slp/pkgs/e/evas evas 1.1.0+svn.69113slp2+build01 828d8bb285397266eb8985fd081fa2692fa3a7d6
Name: evas
Summary: Multi-platform Canvas Library
-Version: 1.2.0+svn.72376slp2+build01
+Version: 1.2.0+svn.73001slp2+build01
Release: 1
Group: System/Libraries
License: BSD
%{_libdir}/evas/modules/savers/*/*/module.so
%{_libdir}/evas/cserve2/loaders/*/*/module.so
%{_bindir}/evas_cserve2_client
+%{_bindir}/evas_cserve2_usage
+%{_bindir}/evas_cserve2_debug
%{_libexecdir}/evas_cserve2
%{_libexecdir}/evas_cserve2_slave
%{_libexecdir}/dummy_slave
SUBDIRS = loaders
libexec_PROGRAMS = evas_cserve2 evas_cserve2_slave dummy_slave
-bin_PROGRAMS = evas_cserve2_client
+bin_PROGRAMS = evas_cserve2_client evas_cserve2_usage evas_cserve2_debug
AM_CPPFLAGS = \
-I. \
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
-DPACKAGE_LIBEXEC_DIR=\"$(libexecdir)\" \
@FREETYPE_CFLAGS@ \
-@EINA_CFLAGS@
+@EINA_CFLAGS@ \
+@EET_CFLAGS@
evas_cserve2_SOURCES = \
evas_cserve2.h \
evas_cserve2_fonts.c \
evas_cserve2_main_loop_linux.c
+libevas_cserve2_utils_la = $(top_builddir)/src/lib/cserve2/libevas_cserve2_utils.la
+
evas_cserve2_LDADD = \
@FREETYPE_LIBS@ \
@EINA_LIBS@ \
-@EFL_SHM_OPEN_LIBS@
+@EFL_SHM_OPEN_LIBS@ \
+@EET_LIBS@ \
+$(libevas_cserve2_utils_la)
evas_cserve2_client_SOURCES = \
evas_cserve2_client.c
+evas_cserve2_usage_SOURCES = \
+evas_cserve2_usage.c
+
+evas_cserve2_debug_SOURCES = \
+evas_cserve2_debug.c
+
+evas_cserve2_usage_LDADD = \
+@EINA_LIBS@
+
+evas_cserve2_debug_LDADD = \
+@EINA_LIBS@
+
evas_cserve2_slave_SOURCES = \
evas_cserve2_slave.c \
evas_cserve2_utils.c
return response_send(fd, ERROR, &err, sizeof(Error_Type));
}
-void *
-cserve2_shm_map(const char *name, size_t length, off_t offset)
+static void *
+_cserve2_shm_map(const char *name, size_t length, off_t offset)
{
void *map;
int fd;
return map;
}
-void
-cserve2_shm_unmap(void *map, size_t length)
+/*
+static 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)
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);
+ char *map = _cserve2_shm_map(shmfile, params->shm.mmap_size,
+ params->shm.mmap_offset);
if (map == MAP_FAILED)
return CSERVE2_RESOURCE_ALLOCATION_FAILED;
#endif
#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_bin_log_dom, __VA_ARGS__)
+#define DEBUG_LOAD_TIME 1
+
extern int _evas_cserve2_bin_log_dom;
typedef struct _Slave Slave;
void *ftdata1; // Freetype file source info comes here
void *ftdata2; // Freetype font info comes here
unsigned int rend_flags;
- unsigned int hint;
unsigned int size;
unsigned int dpi;
const char *name;
const char *file;
+ void *data;
+ int datasize;
};
struct _Slave_Msg_Font_Loaded {
void *ftdata2;
};
+struct _Slave_Msg_Font_Glyphs_Load {
+ struct {
+ void *ftdata1;
+ void *ftdata2;
+ unsigned int rend_flags;
+ unsigned int hint;
+ } font;
+ struct {
+ unsigned int nglyphs;
+ unsigned int *glyphs;
+ } glyphs;
+ struct {
+ Shm_Handle *shm;
+ unsigned int usage;
+ unsigned int nglyphs;
+ } cache;
+};
+
+struct _Slave_Msg_Glyph {
+ unsigned int index;
+ unsigned int offset;
+ unsigned int size;
+ unsigned int rows;
+ unsigned int width;
+ unsigned int pitch;
+ unsigned int num_grays;
+ unsigned int pixel_mode;
+};
+
+typedef struct _Slave_Msg_Glyph Slave_Msg_Glyph;
+
+struct _Slave_Msg_Font_Cache {
+ unsigned int nglyphs;
+ Slave_Msg_Glyph *glyphs;
+ Shm_Handle *shm;
+ unsigned int usage;
+};
+
+typedef struct _Slave_Msg_Font_Cache Slave_Msg_Font_Cache;
+
+struct _Slave_Msg_Font_Glyphs_Loaded {
+ unsigned int ncaches;
+ Slave_Msg_Font_Cache **caches;
+};
+
typedef struct _Slave_Msg_Font_Load Slave_Msg_Font_Load;
typedef struct _Slave_Msg_Font_Loaded Slave_Msg_Font_Loaded;
+typedef struct _Slave_Msg_Font_Glyphs_Load Slave_Msg_Font_Glyphs_Load;
+typedef struct _Slave_Msg_Font_Glyphs_Loaded Slave_Msg_Font_Glyphs_Loaded;
typedef void *(*Font_Request_Msg_Create)(void *data, int *size);
-typedef void (*Font_Request_Msg_Free)(void *data);
+typedef void (*Font_Request_Msg_Free)(void *msg, void *data);
typedef void (*Font_Request_Response)(Client *c, void *data, void *resp, unsigned int rid);
typedef void (*Font_Request_Error)(Client *c, void *data, Error_Type error, unsigned int rid);
CSERVE2_REQ_LAST
} Font_Request_Type;
+typedef struct _Glyph_Entry Glyph_Entry;
+
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? */
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_shm_map(Shm_Handle *shm);
+void cserve2_shm_unmap(Shm_Handle *shm);
+size_t cserve2_shm_size_normalize(size_t size);
void cserve2_command_run(Client *client, Message_Type type);
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);
-int cserve2_cache_font_load(Client *client, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int hint, unsigned int size, unsigned int dpi, unsigned int rid);
+int cserve2_cache_font_load(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int rid);
+int cserve2_cache_font_unload(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int rid);
+int cserve2_cache_font_glyphs_load(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int hint, unsigned int size, unsigned int dpi, unsigned int *glyphs, unsigned int nglyphs, unsigned int rid);
+int cserve2_cache_font_glyphs_used(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int hint, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int *glyphs, unsigned int nglyphs, unsigned int rid);
+void cserve2_cache_stats_get(Client *client, unsigned int rid);
+void cserve2_cache_font_debug(Client *client, unsigned int rid);
Font_Request *cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Font_Request_Funcs *funcs, void *data);
+void cserve2_request_waiter_add(Font_Request *req, unsigned int rid, Client *client);
void cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err);
void cserve2_request_cancel_all(Font_Request *req, Error_Type err);
void cserve2_requests_init(void);
void cserve2_font_init(void);
void cserve2_font_shutdown(void);
void *cserve2_font_slave_cb(Slave_Thread_Data *sd, Slave_Command *cmd, const void *cmddata, void *data);
+void cserve2_font_source_ft_free(void *fontsource);
+void cserve2_font_ft_free(void *fontinfo);
#endif /* _EVAS_CSERVE2_H */
#include <string.h>
+#ifdef DEBUG_LOAD_TIME
+ #include <sys/time.h>
+#endif
+
#include "evas_cserve2.h"
+#include "evas_cs2_utils.h"
typedef struct _Request_Funcs Request_Funcs;
typedef struct _Request Request;
typedef struct _Font_Source Font_Source;
typedef struct _Font_Entry Font_Entry;
typedef struct _Font_Cache Font_Cache;
-typedef struct _Glyph_Entry Glyph_Entry;
typedef void *(*Request_Msg_Create)(Entry *e, int *size);
typedef void (*Request_Response)(Entry *e, void *resp);
Eina_List *references;
Request *request;
Entry_Type type;
+#ifdef DEBUG_LOAD_TIME
+ struct timeval load_start;
+ struct timeval load_finish;
+ int load_time;
+ int saved_time;
+#endif
};
struct _File_Data {
};
struct _Font_Source {
+ const char *key;
const char *name;
const char *file;
int references;
Entry base;
Font_Request *request;
unsigned int rend_flags;
- unsigned int hint;
unsigned int size;
unsigned int dpi;
Font_Source *src;
void *ft;
+ Fash_Glyph2 *glyphs;
+ unsigned int nglyphs;
+ Eina_Inlist *caches;
+ Font_Cache *last_cache;
+ Eina_Bool unused : 1;
+#ifdef DEBUG_LOAD_TIME
+ struct timeval load_start;
+ struct timeval load_finish;
+ int gl_load_time;
+ int gl_saved_time;
+#endif
};
struct _Font_Cache {
+ EINA_INLIST;
Font_Entry *fe;
- struct {
- const char *name;
- void *data;
- unsigned int size;
- unsigned int usage;
- } shm;
+ Shm_Handle *shm;
+ unsigned int usage;
+ int inuse;
Eina_Inlist *glyphs;
+ unsigned int nglyphs;
};
struct _Glyph_Entry {
EINA_INLIST;
Font_Entry *fe;
- Font_Cache *fi;
+ Font_Cache *fc;
unsigned int index;
unsigned int offset;
+ unsigned int size;
+ unsigned int rows;
+ unsigned int width;
+ unsigned int pitch;
+ unsigned int num_grays;
+ unsigned int pixel_mode;
+};
+
+struct _Glyphs_Request {
+ Client *client;
+ Font_Entry *fe;
+ unsigned int current;
+ unsigned int nglyphs;
+ unsigned int *glyphs;
+ unsigned int nrender;
+ unsigned int *render;
+ unsigned int nanswer;
+ Glyph_Entry **answer;
+ unsigned int hint;
};
+typedef struct _Glyphs_Request Glyphs_Request;
+
+struct _Glyphs_Group {
+ Font_Cache *fc;
+ Eina_List *glyphs;
+};
+
+typedef struct _Glyphs_Group Glyphs_Group;
+
struct _Reference {
Client *client;
Entry *entry;
static Eina_List *image_entries_lru = NULL;
+static Eina_List *font_shm_lru = NULL;
+
static int max_unused_mem_usage = 5 * 1024; /* in kbytes */
static int unused_mem_usage = 0;
+static int max_font_usage = 10 * 4 * 1024; /* in kbytes */
+static int font_mem_usage = 0;
+
+#ifdef DEBUG_LOAD_TIME
+static int
+_timeval_sub(const struct timeval *tv2, const struct timeval *tv1)
+{
+ int t1, t2;
+
+ t1 = tv1->tv_usec + tv1->tv_sec * 1000000;
+ t2 = tv2->tv_usec + tv2->tv_sec * 1000000;
+
+ // Make sure that we don't add negative values. Some images may have
+ // been not loaded yet, so it would mess with the stats.
+ if (t2 > t1)
+ return t2 - t1;
+
+ return 0;
+}
+#endif
+
+static inline void
+_entry_load_start(Entry *e)
+{
+#ifdef DEBUG_LOAD_TIME
+ gettimeofday(&e->load_start, NULL);
+#endif
+}
+
+static inline void
+_entry_load_finish(Entry *e)
+{
+#ifdef DEBUG_LOAD_TIME
+ gettimeofday(&e->load_finish, NULL);
+ e->load_time = _timeval_sub(&e->load_finish, &e->load_start);
+#endif
+}
+
+static inline void
+_entry_load_reused(Entry *e)
+{
+#ifdef DEBUG_LOAD_TIME
+ e->saved_time += e->load_time;
+#endif
+}
static void
_image_opened_send(Client *client, File_Data *entry, unsigned int rid)
}
static void
-_font_loaded_send(Client *client, Font_Entry *fe __UNUSED__, unsigned int rid)
+_font_loaded_send(Client *client, unsigned int rid)
{
int size;
Msg_Font_Loaded msg;
DBG("Sending FONT_LOADED reply for RID: %d.", rid);
- memset(&msg, 0, sizeof(msg));
+
+ size = sizeof(msg);
+ memset(&msg, 0, size);
msg.base.rid = rid;
msg.base.type = CSERVE2_FONT_LOADED;
memcpy(buf + sizeof(msg) + pathlen, f->key, keylen);
*bufsize = size;
+
+ _entry_load_start(&f->base);
+
return buf;
}
{
Waiter *w;
+ _entry_load_finish(&e->base);
e->w = resp->w;
e->h = resp->h;
e->frame_count = resp->frame_count;
memcpy(ptr, i->file->loader_data, loaderlen);
*bufsize = size;
+
+ _entry_load_start(&i->base);
+
return buf;
}
{
Waiter *w;
+ _entry_load_finish(&e->base);
+
e->alpha_sparse = resp->alpha_sparse;
if (!e->doload)
DBG("Entry %d loaded by speculative preload.", e->base.id);
}
if (fentry)
- fentry->images = eina_list_remove(fentry->images, entry);
+ {
+ fentry->images = eina_list_remove(fentry->images, entry);
+ if (!fentry->images && !fentry->base.references)
+ eina_hash_del_by_key(file_entries, &fentry->base.id);
+ }
if (entry->shm)
cserve2_shm_unref(entry->shm);
free(entry);
static int
_font_entry_cmp(const Font_Entry *k1, int k1_length __UNUSED__, const Font_Entry *k2, int k2_length __UNUSED__)
{
- if (k1->src->name == k2->src->name)
+ if (k1->src->key == k2->src->key)
{
if (k1->size == k2->size)
{
if (k1->rend_flags == k2->rend_flags)
- {
- if (k1->hint == k2->hint)
- return k1->dpi - k2->dpi;
- return k1->hint - k2->hint;
- }
+ return k1->dpi - k2->dpi;
return k1->rend_flags - k2->rend_flags;
}
return k1->size - k2->size;
}
- return strcmp(k1->src->name, k2->src->name);
+ return strcmp(k1->src->key, k2->src->key);
}
static int
_font_entry_key_hash(const Font_Entry *key, int key_length __UNUSED__)
{
int hash;
- hash = eina_hash_djb2(key->src->name, eina_stringshare_strlen(key->src->name) + 1);
+ hash = eina_hash_djb2(key->src->key, eina_stringshare_strlen(key->src->key) + 1);
hash ^= eina_hash_int32(&key->rend_flags, sizeof(int));
hash ^= eina_hash_int32(&key->size, sizeof(int));
hash ^= eina_hash_int32(&key->dpi, sizeof(int));
static void
_font_entry_free(Font_Entry *fe)
{
+ fash_gl_free(fe->glyphs);
+ fe->src->references--;
+ if (fe->ft) cserve2_font_ft_free(fe->ft);
+ if (fe->src->references <= 0)
+ eina_hash_del_by_key(font_sources, fe->src->key);
free(fe);
}
static void
+_glyph_free_cb(void *data)
+{
+ Glyph_Entry *gl = data;
+ free(gl);
+}
+
+static void
_font_source_free(Font_Source *fs)
{
- if (fs->name) eina_stringshare_del(fs->name);
- if (fs->file) eina_stringshare_del(fs->file);
+ eina_stringshare_del(fs->key);
+ eina_stringshare_del(fs->name);
+ eina_stringshare_del(fs->file);
+ if (fs->ft) cserve2_font_source_ft_free(fs->ft);
free(fs);
}
+static void
+_font_shm_promote(Font_Cache *fc)
+{
+ Eina_List *l;
+ l = eina_list_data_find_list(font_shm_lru, fc);
+ font_shm_lru = eina_list_demote_list(font_shm_lru, l);
+}
+
+static int
+_font_shm_size_get(Font_Cache *fc)
+{
+ int size;
+
+ size = sizeof(*fc) + cserve2_shm_size_get(fc->shm);
+
+ return size;
+}
+
+static void
+_font_shm_free(Font_Cache *fc)
+{
+ Font_Entry *fe = fc->fe;
+ fe->caches = eina_inlist_remove(fe->caches, EINA_INLIST_GET(fc));
+ if (fc == fe->last_cache)
+ fe->last_cache = NULL;
+
+ while (fc->glyphs)
+ {
+ Glyph_Entry *gl = EINA_INLIST_CONTAINER_GET(fc->glyphs, Glyph_Entry);
+ fc->glyphs = eina_inlist_remove(fc->glyphs, fc->glyphs);
+ fash_gl_del(fe->glyphs, gl->index);
+ }
+
+ cserve2_shm_unref(fc->shm);
+ free(fc);
+
+ if (!fe->caches)
+ eina_hash_del_by_key(font_entries, fe);
+}
+
+static void
+_font_shm_lru_flush(void)
+{
+ Eina_List *l, *l_next;
+
+ l = font_shm_lru;
+ l_next = eina_list_next(l);
+
+ while (l && font_mem_usage > max_font_usage)
+ {
+ int size;
+ Font_Cache *fc;
+
+ fc = eina_list_data_get(l);
+ if (fc->fe->unused && fc->inuse == 0)
+ {
+ font_shm_lru = eina_list_remove_list(font_shm_lru, l);
+ size = _font_shm_size_get(fc);
+ size += fc->nglyphs * sizeof(Glyph_Entry);
+ _font_shm_free(fc);
+ font_mem_usage -= size;
+ }
+
+ l = l_next;
+ l_next = eina_list_next(l);
+ }
+}
+
void
cserve2_cache_init(void)
{
void
cserve2_cache_shutdown(void)
{
+ Font_Cache *fc;
+
+ EINA_LIST_FREE(font_shm_lru, fc)
+ _font_shm_free(fc);
+
eina_hash_free(image_entries);
eina_hash_free(image_ids);
eina_hash_free(file_entries);
if (fentry->invalid)
_file_entry_free(fentry);
- else
- {
- Image_Data *ie;
- EINA_LIST_FREE(fentry->images, ie)
- ie->file = NULL;
- eina_hash_del_by_key(file_entries, &entry->id);
- }
+ else if (!fentry->images)
+ eina_hash_del_by_key(file_entries, &entry->id);
+ /* don't free file entries that have images attached to it, they will
+ * be freed when the last unused image is freed */
}
else if (entry->type == CSERVE2_IMAGE_DATA)
{
else if (entry->type == CSERVE2_FONT_ENTRY)
{
Font_Entry *fe = (Font_Entry *)entry;
- eina_hash_del_by_key(font_entries, fe);
+ fe->unused = EINA_TRUE;
+ if (!fe->caches)
+ eina_hash_del_by_key(font_entries, fe);
}
else
ERR("Wrong type of entry.");
}
static void
-_font_entry_reference_del(Client *client, Reference *ref)
+_font_entry_reference_del(Client *client, Font_Entry *fe)
{
- Entry *entry = ref->entry;
+ Eina_List *l;
+ Reference *ref;
- _entry_reference_del(entry, ref);
+ EINA_LIST_FOREACH(client->fonts.referencing, l, ref)
+ {
+ if (ref->entry == (Entry *)fe)
+ {
+ ref->count--;
+ if (ref->count > 0)
+ break;
+
+ client->fonts.referencing = eina_list_remove_list(
+ client->fonts.referencing, l);
+ _entry_reference_del(&fe->base, ref);
+ return;
+ }
+ }
}
void
EINA_LIST_FREE(client->fonts.referencing, ref)
{
- _font_entry_reference_del(client, ref);
+ _entry_reference_del(ref->entry, ref);
}
}
}
static Font_Entry *
-_cserve2_font_entry_find(const char *name, unsigned int namelen, unsigned int size, unsigned int rend_flags, unsigned int hint, unsigned int dpi)
+_cserve2_font_entry_find(const char *name, unsigned int namelen, unsigned int size, unsigned int rend_flags, unsigned int dpi)
{
Font_Entry tmp_fe;
Font_Source tmp_fs;
Font_Entry *fe;
- tmp_fs.name = eina_stringshare_add_length(name, namelen);
+ tmp_fs.key = eina_stringshare_add_length(name, namelen);
tmp_fe.src = &tmp_fs;
tmp_fe.size = size;
tmp_fe.rend_flags = rend_flags;
- tmp_fe.hint = hint;
tmp_fe.dpi = dpi;
fe = eina_hash_find(font_entries, &tmp_fe);
- eina_stringshare_del(tmp_fs.name);
+ eina_stringshare_del(tmp_fs.key);
return fe;
}
msg->ftdata1 = fe->src->ft;
msg->ftdata2 = fe->ft;
msg->rend_flags = fe->rend_flags;
- msg->hint = fe->hint;
msg->size = fe->size;
msg->dpi = fe->dpi;
msg->name = fe->src->name;
*size = 0;
+ _entry_load_start(&fe->base);
+
return msg;
}
static void
-_font_load_request_free(void *data)
+_font_load_request_free(void *msg, void *data __UNUSED__)
{
- free(data);
+ free(msg);
}
static void
-_font_load_request_response(Client *client, void *data, void *resp, unsigned int rid)
+_font_load_request_response(Client *client __UNUSED__, void *data, void *resp, unsigned int rid __UNUSED__)
{
Slave_Msg_Font_Loaded *msg = resp;
Font_Entry *fe = data;
+ DBG("request %d answered.", rid);
+
if (!fe->src->ft)
fe->src->ft = msg->ftdata1;
if (!fe->ft)
- fe->ft = msg->ftdata2;
+ {
+ fe->ft = msg->ftdata2;
+ _entry_load_finish(&fe->base);
+ }
if (fe->request) fe->request = NULL;
+
+ _font_loaded_send(client, rid);
}
static void
-_font_load_request_failed(Client *client, void *data, Error_Type error, unsigned int rid)
+_font_load_request_failed(Client *client __UNUSED__, void *data __UNUSED__, Error_Type error __UNUSED__, unsigned int rid __UNUSED__)
{
+ Font_Entry *fe = data;
+ DBG("request %d error answered.", rid);
+
+ cserve2_client_error_send(client, rid, error);
+
+ if (fe->request) fe->request = NULL;
+
+ _font_entry_reference_del(client, fe);
}
static Font_Request_Funcs _font_load_funcs = {
.error = (Font_Request_Error)_font_load_request_failed
};
+static Eina_Bool
+_glyphs_request_check(Glyphs_Request *req, Eina_Bool report_load)
+{
+ unsigned int i;
+ Font_Entry *fe = req->fe;
+
+ req->answer = malloc(sizeof(*req->answer) * req->nglyphs);
+ req->nanswer = 0;
+
+ for (i = req->current; i < req->nglyphs; i++)
+ {
+ Glyph_Entry *ge;
+ ge = fash_gl_find(fe->glyphs, req->glyphs[i]);
+ if (ge)
+ {
+ req->answer[req->nanswer++] = ge;
+#ifdef DEBUG_LOAD_TIME
+ // calculate average time saved when loading glyphs
+ if (report_load)
+ fe->gl_saved_time +=
+ (fe->gl_load_time / fe->nglyphs);
+#endif
+ ge->fc->inuse++;
+ }
+ else
+ break;
+ }
+
+ req->current = i;
+
+ // No glyphs need to be rendered.
+ return (req->nanswer == req->nglyphs);
+}
+
+/* organize answer (cache1{gl1, gl2,}, cache2{gl3,gl4,gl5}, cache3{gl6})
+ */
+static Eina_List *
+_glyphs_group_create(Glyphs_Request *req)
+{
+ Eina_List *groups = NULL;
+ unsigned int i;
+
+ for (i = 0; i < req->nanswer; i++)
+ {
+ Eina_List *l;
+ Glyphs_Group *iter, *gg = NULL;
+ Font_Cache *fc = req->answer[i]->fc;
+
+ EINA_LIST_FOREACH(groups, l, iter)
+ {
+ if (iter->fc == fc)
+ {
+ gg = iter;
+ break;
+ }
+ }
+
+ if (!gg)
+ {
+ gg = calloc(1, sizeof(*gg));
+ gg->fc = fc;
+ groups = eina_list_append(groups, gg);
+ }
+ gg->glyphs = eina_list_append(gg->glyphs, req->answer[i]);
+ }
+
+ return groups;
+}
+
+static void
+_glyphs_loaded_send(Glyphs_Request *req, unsigned int rid)
+{
+ Msg_Font_Glyphs_Loaded msg;
+ unsigned int size;
+ Eina_List *ll, *answers = NULL;
+ const char *shmname;
+ unsigned int shmsize;
+ unsigned int intsize;
+ char *resp, *buf;
+ Glyphs_Group *iter;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.base.rid = rid;
+ msg.base.type = CSERVE2_FONT_GLYPHS_LOADED;
+
+ answers = _glyphs_group_create(req);
+ msg.ncaches = eina_list_count(answers);
+ size = sizeof(msg);
+
+ // calculate size of message
+ // ncaches * sizeof(cache) + nglyphs1 * sizeof(glyph) +
+ // nglyphs2 * sizeof(glyph)...
+
+ intsize = sizeof(unsigned int);
+
+ EINA_LIST_FOREACH(answers, ll, iter)
+ {
+ shmname = cserve2_shm_name_get(iter->fc->shm);
+ shmsize = eina_stringshare_strlen(shmname) + 1;
+ // shm namelen + name
+ size += intsize + shmsize;
+
+ // nglyphs
+ size += intsize;
+ // nglyphs * (index + offset + size + rows + width + pitch +
+ // num_grays + pixel_mode)
+ size += eina_list_count(iter->glyphs) * 8 * intsize;
+ }
+
+ resp = malloc(size);
+ memcpy(resp, &msg, sizeof(msg));
+ buf = resp + sizeof(msg);
+
+ EINA_LIST_FREE(answers, iter)
+ {
+ Glyph_Entry *gl;
+ unsigned int nglyphs;
+
+ shmname = cserve2_shm_name_get(iter->fc->shm);
+ shmsize = eina_stringshare_strlen(shmname) + 1;
+ memcpy(buf, &shmsize, intsize);
+ buf += intsize;
+ memcpy(buf, shmname, shmsize);
+ buf += shmsize;
+
+ nglyphs = eina_list_count(iter->glyphs);
+ memcpy(buf, &nglyphs, intsize);
+ buf += intsize;
+
+ iter->fc->inuse -= eina_list_count(iter->glyphs);
+
+ EINA_LIST_FREE(iter->glyphs, gl)
+ {
+ memcpy(buf, &gl->index, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->offset, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->size, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->rows, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->width, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->pitch, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->num_grays, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->pixel_mode, intsize);
+ buf += intsize;
+ }
+
+ /* We are removing SHMs from the beginning of the list, so this
+ * gives a higher priority to them */
+ _font_shm_promote(iter->fc);
+ eina_list_free(iter->glyphs);
+ free(iter);
+ }
+
+ cserve2_client_send(req->client, &size, sizeof(size));
+ cserve2_client_send(req->client, resp, size);
+
+ free(resp);
+}
+
+/*
+ * taken from evas_path.c. It would be good to clean up those utils to
+ * have cserve link against them easily without dragging unneeded dependencies
+ */
+#ifdef _WIN32
+# define EVAS_PATH_SEPARATOR "\\"
+#else
+# define EVAS_PATH_SEPARATOR "/"
+#endif
+
+static char *
+_file_path_join(const char *path, const char *end)
+{
+ char *res = NULL;
+ size_t len;
+
+ if ((!path) && (!end)) return NULL;
+ if (!path) return strdup(end);
+ if (!end) return strdup(path);
+ len = strlen(path);
+ len += strlen(end);
+ len += strlen(EVAS_PATH_SEPARATOR);
+ res = malloc(len + 1);
+ if (!res) return NULL;
+ strcpy(res, path);
+ strcat(res, EVAS_PATH_SEPARATOR);
+ strcat(res, end);
+ return res;
+}
+
+static Glyphs_Request *
+_glyphs_request_create(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int hint, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int *glyphs, unsigned int nglyphs)
+{
+ char *fullname;
+ Glyphs_Request *req = calloc(1, sizeof(*req));
+
+ if (sourcelen == 0)
+ source = NULL;
+ if (namelen == 0)
+ name = NULL;
+
+ fullname = _file_path_join(source, name);
+ req->fe = _cserve2_font_entry_find(fullname, strlen(fullname) + 1, size,
+ rend_flags, dpi);
+ free(fullname);
+ if (!req->fe)
+ {
+ ERR("No font entry found: source %s, name %s, rendflags: %d, hint: %d,"
+ " size: %d, dpi: %d", source, name, rend_flags, hint, size, dpi);
+ free(req);
+ return NULL;
+ }
+
+ req->client = client;
+
+ req->nglyphs = nglyphs;
+ req->current = 0;
+ req->glyphs = glyphs;
+ req->hint = hint;
+
+ return req;
+}
+
+static void
+_glyphs_request_free(Glyphs_Request *req)
+{
+ free(req->glyphs);
+ free(req->render);
+ free(req->answer);
+ free(req);
+}
+
+/* add glyphs that are already in cache to the "answers" array, and the ones
+ * that are not cached to the "render" array.
+ */
+static void
+_glyphs_load_request_prepare(Glyphs_Request *req)
+{
+ unsigned int i, max;
+ req->nrender = 0;
+ Font_Entry *fe = req->fe;
+
+ if (!fe)
+ {
+ ERR("No font entry for this request.");
+ return;
+ }
+
+ // Won't render more than this number of glyphs
+ max = req->nglyphs - req->nanswer;
+ req->render = malloc(sizeof(*req->render) * max);
+
+ for (i = req->current; i < req->nglyphs; i++)
+ {
+ Glyph_Entry *ge;
+ ge = fash_gl_find(fe->glyphs, req->glyphs[i]);
+ if (ge)
+ {
+ req->answer[req->nanswer++] = ge;
+
+#ifdef DEBUG_LOAD_TIME
+ // calculate average time saved when loading glyphs
+ fe->gl_saved_time +=
+ (fe->gl_load_time / fe->nglyphs);
+#endif
+ ge->fc->inuse++;
+ }
+ else
+ req->render[req->nrender++] = req->glyphs[i];
+ }
+}
+
+static void *
+_glyphs_load_request_build(void *data, int *size __UNUSED__)
+{
+ Glyphs_Request *req = data;
+ Slave_Msg_Font_Glyphs_Load *msg = NULL;
+ Font_Entry *fe = req->fe;
+ Font_Cache *fc;
+
+ _glyphs_load_request_prepare(req);
+
+ msg = calloc(1, sizeof(*msg));
+
+ msg->font.ftdata1 = fe->src->ft;
+ msg->font.ftdata2 = fe->ft;
+ msg->font.hint = req->hint;
+ msg->font.rend_flags = fe->rend_flags;
+ msg->glyphs.nglyphs = req->nrender;
+ msg->glyphs.glyphs = req->render;
+
+ // Trying to reuse last filled cache.
+ fc = fe->last_cache;
+ if (fc)
+ {
+ msg->cache.shm = fc->shm;
+ msg->cache.usage = fc->usage;
+ msg->cache.nglyphs = fc->nglyphs;
+ }
+
+#ifdef DEBUG_LOAD_TIME
+ gettimeofday(&fe->load_start, NULL);
+#endif
+
+ return msg;
+}
+
+static void
+_glyphs_load_request_free(void *msg, void *data)
+{
+ _glyphs_request_free(data);
+ free(msg);
+}
+
+static void
+_glyphs_load_request_response(Client *client __UNUSED__, void *data, void *resp, unsigned int rid)
+{
+ Glyphs_Request *req = data;
+ Slave_Msg_Font_Glyphs_Loaded *msg = resp;
+ Font_Entry *fe = req->fe;
+ Font_Cache *fc = NULL;
+ unsigned int i = 0;
+
+ if (fe->last_cache && fe->last_cache->shm == msg->caches[0]->shm)
+ fc = fe->last_cache;
+
+ while (i < msg->ncaches)
+ {
+ unsigned int j;
+ Slave_Msg_Font_Cache *c = msg->caches[i++];
+
+ if (!fc)
+ {
+ fc = malloc(sizeof(*fc));
+ fe->caches = eina_inlist_append(fe->caches, EINA_INLIST_GET(fc));
+ fe->last_cache = fc;
+ fc->fe = fe;
+ fc->shm = c->shm;
+ fc->glyphs = NULL;
+ fc->nglyphs = 0;
+ fc->inuse = 0;
+ font_shm_lru = eina_list_append(font_shm_lru, fc);
+ font_mem_usage += _font_shm_size_get(fc);
+ }
+ fc->usage = c->usage;
+ for (j = 0; j < c->nglyphs; j++)
+ {
+ Glyph_Entry *gl = malloc(sizeof(*gl));
+ gl->fe = fe;
+ gl->fc = fc;
+ gl->index = c->glyphs[j].index;
+ gl->offset = c->glyphs[j].offset;
+ gl->size = c->glyphs[j].size;
+ gl->rows = c->glyphs[j].rows;
+ gl->width = c->glyphs[j].width;
+ gl->pitch = c->glyphs[j].pitch;
+ gl->num_grays = c->glyphs[j].num_grays;
+ gl->pixel_mode = c->glyphs[j].pixel_mode;
+ font_mem_usage += sizeof(*gl);
+ fc->glyphs = eina_inlist_append(fc->glyphs, EINA_INLIST_GET(gl));
+ fc->nglyphs++;
+ fe->nglyphs++;
+ fash_gl_add(fe->glyphs, gl->index, gl);
+ req->answer[req->nanswer++] = gl;
+ gl->fc->inuse++;
+ }
+
+ free(c); // FIXME: We are freeing this here because we only do a
+ // simple free on the response message. Later we need to
+ // setup a free callback for the slave response.
+ fc = NULL;
+ }
+
+#ifdef DEBUG_LOAD_TIME
+ int load_time;
+ gettimeofday(&fe->load_finish, NULL);
+ load_time = _timeval_sub(&fe->load_finish, &fe->load_start);
+ fe->gl_load_time += load_time;
+#endif
+
+ _glyphs_loaded_send(req, rid);
+ _font_shm_lru_flush();
+}
+
+static void
+_glyphs_load_request_failed(Client *client __UNUSED__, void *data __UNUSED__, Error_Type error __UNUSED__, unsigned int rid __UNUSED__)
+{
+}
+
+static Font_Request_Funcs _glyphs_load_funcs = {
+ .msg_create = (Font_Request_Msg_Create)_glyphs_load_request_build,
+ .msg_free = (Font_Request_Msg_Free)_glyphs_load_request_free,
+ .response = (Font_Request_Response)_glyphs_load_request_response,
+ .error = (Font_Request_Error)_glyphs_load_request_failed
+};
+
+static Eina_Bool
+_font_entry_stats_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata)
+{
+ Font_Entry *fe = data;
+ Msg_Stats *msg = fdata;
+ Font_Cache *fc;
+ int nrefs = eina_list_count(fe->base.references);
+
+ msg->fonts.fonts_loaded++;
+ if (fe->unused) msg->fonts.fonts_unused++;
+
+ // accounting size
+ EINA_INLIST_FOREACH(fe->caches, fc)
+ {
+ unsigned int fc_usage, shmsize;
+ /* This is not real requested usage, but an approximation. We don't
+ * know how many times each glyph would be used by each client, but
+ * assume that a similar set of glyphs from a given font would be used
+ * by each client, thus counting them one time per client referencing
+ * them.
+ */
+ fc_usage = fc->usage * nrefs;
+ shmsize = cserve2_shm_size_get(fc->shm);
+
+ msg->fonts.requested_size += fc_usage;
+ msg->fonts.real_size += shmsize;
+ if (fe->unused) msg->fonts.unused_size += shmsize;
+ }
+
+#ifdef DEBUG_LOAD_TIME
+ // accounting fonts load time
+ msg->fonts.fonts_load_time += fe->base.load_time;
+ if (fe->caches)
+ {
+ msg->fonts.fonts_used_load_time += fe->base.load_time;
+ msg->fonts.fonts_used_saved_time += fe->base.saved_time;
+ }
+
+ // accounting glyphs load time
+ msg->fonts.glyphs_load_time += fe->gl_load_time;
+ msg->fonts.glyphs_saved_time += fe->gl_saved_time;
+#endif
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_image_file_entry_stats_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata)
+{
+ Msg_Stats *msg = fdata;
+ File_Data *fd = data;
+
+ // accounting numbers
+ msg->images.files_loaded++;
+
+ // accounting size
+ msg->images.files_size += sizeof(File_Data) +
+ eina_list_count(fd->images) * sizeof(Eina_List *) +
+ eina_list_count(fd->base.references) *
+ (sizeof(Request) + sizeof(Eina_List *));
+
+#ifdef DEBUG_LOAD_TIME
+ // accounting file entries load time
+ msg->images.files_load_time += fd->base.load_time;
+ msg->images.files_saved_time += fd->base.saved_time;
+#endif
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_image_data_entry_stats_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata)
+{
+ Msg_Stats *msg = fdata;
+ Image_Data *id = data;
+ unsigned int image_size;
+
+ // accounting numbers
+ msg->images.images_loaded++;
+ if (id->unused) msg->images.images_unused++;
+
+ // accounting size
+ msg->images.images_size += _image_entry_size_get(id) * 1024;
+ if (id->unused) msg->images.unused_size += _image_entry_size_get(id) * 1024;
+
+ image_size = id->file->w * id->file->h * 4;
+ msg->images.requested_size +=
+ (image_size * eina_list_count(id->base.references));
+
+#ifdef DEBUG_LOAD_TIME
+ // accounting image entries load time
+ msg->images.images_load_time += id->base.load_time;
+ msg->images.images_saved_time += id->base.saved_time;
+#endif
+
+ return EINA_TRUE;
+}
+
+static void
+_cserve2_cache_image_stats_get(Msg_Stats *msg)
+{
+ eina_hash_foreach(file_entries, _image_file_entry_stats_cb, msg);
+ eina_hash_foreach(image_entries, _image_data_entry_stats_cb, msg);
+}
+
+static void
+_cserve2_cache_font_stats_get(Msg_Stats *msg)
+{
+ eina_hash_foreach(font_entries, _font_entry_stats_cb, msg);
+}
+
+struct _debug_info
+{
+ unsigned int size;
+ unsigned int nfonts;
+};
+
+static Eina_Bool
+_font_entry_debug_size_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata)
+{
+ struct _debug_info *di = fdata;
+ unsigned int size = di->size;
+ Font_Entry *fe = data;
+ Font_Cache *fc;
+ unsigned int intsize = sizeof(unsigned int);
+
+ // filelen
+ size += intsize;
+
+ // file
+ if (fe->src->file)
+ size += strlen(fe->src->file) + 1;
+
+ // namelen
+ size += intsize;
+
+ // name
+ if (fe->src->name)
+ size += strlen(fe->src->name) + 1;
+
+ // rend_flags, size, dpi
+ size += 3 * intsize;
+
+ // unused
+ size += intsize;
+
+ // ncaches
+ size += intsize;
+
+ EINA_INLIST_FOREACH(fe->caches, fc)
+ {
+ Glyph_Entry *gl;
+
+ // shmnamelen + shmname
+ size += intsize;
+ size += strlen(cserve2_shm_name_get(fc->shm)) + 1;
+
+ // size + usage
+ size += 2 * intsize;
+
+ // nglyphs
+ size += intsize;
+
+ EINA_INLIST_FOREACH(fc->glyphs, gl)
+ {
+ // index, offset, size
+ size += 3 * intsize;
+
+ // rows, width, pitch
+ size += 3 * intsize;
+
+ // num_grays, pixel_mode
+ size += 2 * intsize;
+ }
+ }
+
+ di->size = size;
+ di->nfonts++;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_font_entry_debug_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata)
+{
+ char **pos = fdata;
+ char *buf = *pos;
+ Font_Entry *fe = data;
+ Font_Cache *fc;
+ unsigned int len;
+ unsigned int unused;
+ unsigned int ncaches;
+ unsigned int intsize = sizeof(unsigned int);
+
+ // filelen + file
+ len = 0;
+ if (fe->src->file)
+ len = strlen(fe->src->file) + 1;
+ memcpy(buf, &len, intsize);
+ buf += intsize;
+ memcpy(buf, fe->src->file, len);
+ buf += len;
+
+ // namelen + name
+ len = 0;
+ if (fe->src->name)
+ len = strlen(fe->src->name) + 1;
+ memcpy(buf, &len, intsize);
+ buf += intsize;
+ memcpy(buf, fe->src->name, len);
+ buf += len;
+
+ // rend_flags, size, dpi
+ memcpy(buf, &fe->rend_flags, intsize);
+ buf += intsize;
+ memcpy(buf, &fe->size, intsize);
+ buf += intsize;
+ memcpy(buf, &fe->dpi, intsize);
+ buf += intsize;
+
+ // unused
+ unused = fe->unused;
+ memcpy(buf, &unused, intsize);
+ buf += intsize;
+
+ // ncaches
+ ncaches = eina_inlist_count(fe->caches);
+ memcpy(buf, &ncaches, intsize);
+ buf += intsize;
+
+ EINA_INLIST_FOREACH(fe->caches, fc)
+ {
+ Glyph_Entry *gl;
+ const char *shmname;
+ unsigned int shmsize;
+
+ // shmnamelen + shmname
+ shmname = cserve2_shm_name_get(fc->shm);
+ len = strlen(shmname) + 1;
+ memcpy(buf, &len, intsize);
+ buf += intsize;
+ memcpy(buf, shmname, len);
+ buf += len;
+
+ // size, usage, nglyphs
+ shmsize = cserve2_shm_size_get(fc->shm);
+ memcpy(buf, &shmsize, intsize);
+ buf += intsize;
+ memcpy(buf, &fc->usage, intsize);
+ buf += intsize;
+ memcpy(buf, &fc->nglyphs, intsize);
+ buf += intsize;
+
+ EINA_INLIST_FOREACH(fc->glyphs, gl)
+ {
+ // index, offset, size
+ memcpy(buf, &gl->index, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->offset, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->size, intsize);
+ buf += intsize;
+
+ // rows, width, pitch
+ memcpy(buf, &gl->rows, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->width, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->pitch, intsize);
+ buf += intsize;
+
+ // num_grays, pixel_mode
+ memcpy(buf, &gl->num_grays, intsize);
+ buf += intsize;
+ memcpy(buf, &gl->pixel_mode, intsize);
+ buf += intsize;
+ }
+ }
+
+ *pos = buf;
+ return EINA_TRUE;
+}
+
+static void *
+_cserve2_cache_font_debug(unsigned int rid, unsigned int *size)
+{
+ Msg_Font_Debug msg;
+ char *buf, *pos;
+ struct _debug_info di;
+ di.size = sizeof(msg);
+ di.nfonts = 0;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.base.type = CSERVE2_FONT_DEBUG;
+ msg.base.rid = rid;
+
+ // First calculate how much size is needed for this message:
+
+ // nfonts
+ di.size += sizeof(unsigned int);
+
+ // size needed for each font entry
+ eina_hash_foreach(font_entries, _font_entry_debug_size_cb, &di);
+
+ // Now really create the message
+ buf = malloc(di.size);
+ pos = buf;
+
+ // msg base
+ memcpy(buf, &msg, sizeof(msg));
+ pos += sizeof(msg);
+
+ // nfonts
+ memcpy(pos, &di.nfonts, sizeof(unsigned int));
+ pos += sizeof(unsigned int);
+
+ eina_hash_foreach(font_entries, _font_entry_debug_cb, &pos);
+
+ *size = di.size;
+ return buf;
+}
+
int
cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid)
{
if (ref)
{
entry = (File_Data *)ref->entry;
+ _entry_load_reused(ref->entry);
if (entry->invalid)
{
// search whether the file is already opened by another client
snprintf(buf, sizeof(buf), "%s:%s", path, key);
- file_id = (unsigned int)eina_hash_find(file_ids, buf);
+ file_id = (unsigned int)(uintptr_t)eina_hash_find(file_ids, buf);
if (file_id)
{
DBG("found file_id %u for client file id %d",
return -1;
}
ref = _entry_reference_add((Entry *)entry, client, client_file_id);
+ _entry_load_reused(ref->entry);
eina_hash_add(client->files.referencing, &client_file_id, ref);
if (entry->base.request)
_request_answer_add(entry->base.request, ref, rid, CSERVE2_OPEN);
entry->key = strdup(key);
entry->base.id = file_id;
eina_hash_add(file_entries, &file_id, entry);
- eina_hash_add(file_ids, buf, (void *)file_id);
+ eina_hash_add(file_ids, buf, (intptr_t*)(int64_t)file_id);
ref = _entry_reference_add((Entry *)entry, client, client_file_id);
eina_hash_add(client->files.referencing, &client_file_id, ref);
image_entries_lru = eina_list_remove(image_entries_lru, entry);
unused_mem_usage -= _image_entry_size_get(entry);
}
+ _entry_load_reused(&entry->base);
if (oldref && (oldref->entry->id == image_id))
return 0;
entry->base.id = image_id;
eina_hash_add(image_entries, &image_id, entry);
- eina_hash_add(image_ids, buf, (void *)image_id);
+ eina_hash_add(image_ids, buf, (intptr_t *)(int64_t)image_id);
ref = _entry_reference_add((Entry *)entry, client, msg->image_id);
if (oldref)
}
int
-cserve2_cache_font_load(Client *client, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int hint, unsigned int size, unsigned int dpi, unsigned int rid)
+cserve2_cache_font_load(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int rid)
{
Reference *ref;
Font_Source *fs;
- Font_Entry *fe = _cserve2_font_entry_find(name, namelen, size,
- rend_flags, hint, dpi);
+ Font_Entry *fe;
+ char *fullname;
+
+ if (sourcelen == 0)
+ source = NULL;
+ if (namelen == 0)
+ name = NULL;
+ fullname = _file_path_join(source, name);
+ fe = _cserve2_font_entry_find(fullname, strlen(fullname) + 1, size,
+ rend_flags, dpi);
if (fe)
{
- DBG("found font entry %s, rendflags: %d, hint: %d, size: %d, dpi: %d",
- name, rend_flags, hint, size, dpi);
+ DBG("found font entry %s, rendflags: %d, size: %d, dpi: %d",
+ name, rend_flags, size, dpi);
ref = _entry_reference_add((Entry *)fe, client, 0);
client->fonts.referencing = eina_list_append(
client->fonts.referencing, ref);
- _font_loaded_send(client, fe, rid);
+ _entry_load_reused(&fe->base);
+ fe->unused = EINA_FALSE;
+
+ if (fe->request)
+ cserve2_request_waiter_add(fe->request, rid, client);
+ else
+ _font_loaded_send(client, rid);
+ free(fullname);
return 0;
}
fe = calloc(1, sizeof(*fe));
fe->rend_flags = rend_flags;
- fe->hint = hint;
fe->size = size;
fe->dpi = dpi;
fe->base.type = CSERVE2_FONT_ENTRY;
+ fe->glyphs = fash_gl_new(_glyph_free_cb);
+ ref = _entry_reference_add((Entry *)fe, client, 0);
+ client->fonts.referencing = eina_list_append(
+ client->fonts.referencing, ref);
+ fe->unused = EINA_FALSE;
- fs = _cserve2_font_source_find(name);
+ fs = _cserve2_font_source_find(fullname);
if (!fs)
{
fs = calloc(1, sizeof(*fs));
- fs->name = eina_stringshare_add_length(name, namelen);
- fs->file = eina_stringshare_ref(fs->name);
- eina_hash_direct_add(font_sources, fs->name, fs);
+ if (source)
+ {
+ fs->key = eina_stringshare_add(fullname);
+ fs->name = eina_stringshare_add_length(name, namelen);
+ fs->file = eina_stringshare_add_length(source, sourcelen);
+ }
+ else
+ {
+ fs->file = eina_stringshare_add_length(name, namelen);
+ fs->key = eina_stringshare_ref(fs->file);
+ }
+ eina_hash_direct_add(font_sources, fs->key, fs);
}
-
fe->src = fs;
fs->references++;
+ DBG("adding FONT_LOAD '%s' request.", fs->name);
fe->request = cserve2_request_add(CSERVE2_REQ_FONT_LOAD, rid,
client, &_font_load_funcs, fe);
eina_hash_direct_add(font_entries, fe, fe);
+ free(fullname);
+
+ return 0;
+}
+
+int
+cserve2_cache_font_unload(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int rid __UNUSED__)
+{
+ Font_Entry *fe;
+ char *fullname;
+
+ if (sourcelen == 0)
+ source = NULL;
+ if (namelen == 0)
+ name = NULL;
+
+ fullname = _file_path_join(source, name);
+ fe = _cserve2_font_entry_find(fullname, strlen(fullname) + 1, size,
+ rend_flags, dpi);
+ free(fullname);
+
+ if (!fe)
+ {
+ ERR("Unreferencing font not found: '%s:%s'.", source, name);
+ return -1;
+ }
+
+ _font_entry_reference_del(client, fe);
+
+ return 0;
+}
+
+int
+cserve2_cache_font_glyphs_load(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int hint, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int *glyphs, unsigned int nglyphs, unsigned int rid)
+{
+ Glyphs_Request *req;
+
+ req = _glyphs_request_create(client, source, sourcelen, name, namelen,
+ hint, rend_flags, size, dpi, glyphs, nglyphs);
+ if (!req)
+ {
+ free(glyphs);
+ return -1;
+ }
+
+ if (_glyphs_request_check(req, EINA_TRUE))
+ {
+ INF("Glyphs already loaded. Sending answer.");
+ _glyphs_loaded_send(req, rid);
+ _glyphs_request_free(req);
+ }
+ else
+ {
+ cserve2_request_add(CSERVE2_REQ_FONT_GLYPHS_LOAD, rid,
+ client, &_glyphs_load_funcs, req);
+ }
+ return 0;
+}
+
+int
+cserve2_cache_font_glyphs_used(Client *client, const char *source, unsigned int sourcelen, const char *name, unsigned int namelen, unsigned int hint, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int *glyphs, unsigned int nglyphs, unsigned int rid __UNUSED__)
+{
+ Glyphs_Group *gg;
+ Eina_List *groups;
+ Glyphs_Request *req;
+
+ DBG("Received report of used glyphs from client %d", client->id);
+ req = _glyphs_request_create(client, source, sourcelen, name, namelen,
+ hint, rend_flags, size, dpi, glyphs, nglyphs);
+ if (!req)
+ {
+ free(glyphs);
+ return 0;
+ }
+
+ _glyphs_request_check(req, EINA_FALSE);
+ groups = _glyphs_group_create(req);
+
+ // Promote SHMs which are still cached and in use
+ // TODO: We can use later the information from request_prepare to preload
+ // glyphs which are not cached anymore, but are in use on the client.
+ EINA_LIST_FREE(groups, gg)
+ {
+ _font_shm_promote(gg->fc);
+ eina_list_free(gg->glyphs);
+ free(gg);
+ }
+
+ _glyphs_request_free(req);
return 0;
}
req->entry->request = NULL;
free(req);
}
+
+void
+cserve2_cache_stats_get(Client *client, unsigned int rid)
+{
+ Msg_Stats msg;
+ int size;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.base.type = CSERVE2_STATS;
+ msg.base.rid = rid;
+
+ _cserve2_cache_image_stats_get(&msg);
+ _cserve2_cache_font_stats_get(&msg);
+
+ size = sizeof(msg);
+ cserve2_client_send(client, &size, sizeof(size));
+ cserve2_client_send(client, &msg, size);
+}
+
+void
+cserve2_cache_font_debug(Client *client, unsigned int rid)
+{
+ void *msg;
+ unsigned int size;
+
+ msg = _cserve2_cache_font_debug(rid, &size);
+
+ cserve2_client_send(client, &size, sizeof(size));
+ cserve2_client_send(client, msg, size);
+
+ free(msg);
+}
#include "evas_cserve2.h"
-static const char *SOCK_PATH = "/tmp/cserve2.socket";
static unsigned int _rid_count = 0;
static struct sockaddr_un socket_local;
--- /dev/null
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <Eina.h>
+
+#include "evas_cs2.h"
+
+static int socketfd = -1;
+static unsigned int _rid_count = 1;
+static int _evas_cserve2_debug_log_dom = -1;
+
+static struct sockaddr_un socksize;
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX sizeof(socksize.sun_path)
+#endif
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_debug_log_dom, __VA_ARGS__)
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_debug_log_dom, __VA_ARGS__)
+#ifdef WRN
+#undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_debug_log_dom, __VA_ARGS__)
+#ifdef INF
+#undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_debug_log_dom, __VA_ARGS__)
+
+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;
+ }
+
+ snprintf(buf, sizeof(buf), "/tmp/.evas-cserve2-%x.socket", (int)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 Eina_Bool
+_server_send(const void *data, int size)
+{
+ int sent = 0;
+ ssize_t ret;
+ const char *msg = data;
+
+ while (sent < size)
+ {
+ ret = send(socketfd, msg + sent, size - sent, MSG_NOSIGNAL);
+ if (ret < 0)
+ {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ return EINA_FALSE;
+ }
+ sent += ret;
+ }
+
+ 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;
+}
+
+static void
+_debug_msg_send(void)
+{
+ Msg_Base msg;
+ int size;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.type = CSERVE2_FONT_DEBUG;
+ msg.rid = _rid_count++;
+
+ size = sizeof(msg);
+
+ if (!_server_send(&size, sizeof(size)))
+ {
+ ERR("Could not send usage msg size to server.");
+ return;
+ }
+ if (!_server_send(&msg, size))
+ {
+ ERR("Could not send usage msg body to server.");
+ return;
+ }
+}
+
+typedef struct _Font_Entry Font_Entry;
+typedef struct _Cache_Entry Cache_Entry;
+typedef struct _Glyph_Entry Glyph_Entry;
+
+struct _Font_Entry
+{
+ const char *file;
+ const char *name;
+ unsigned int rend_flags;
+ unsigned int size;
+ unsigned int dpi;
+ unsigned int unused;
+ Eina_List *caches;
+};
+
+struct _Cache_Entry
+{
+ const char *shmname;
+ unsigned int size;
+ unsigned int usage;
+ Eina_List *glyphs;
+};
+
+struct _Glyph_Entry
+{
+ unsigned int index;
+ unsigned int offset;
+ unsigned int size;
+ unsigned int rows;
+ unsigned int width;
+ unsigned int pitch;
+ unsigned int num_grays;
+ unsigned int pixel_mode;
+};
+
+#define READIT(_dst, _src) \
+ do { \
+ memcpy(&_dst, _src, sizeof(_dst)); \
+ _src += sizeof(_dst); \
+ } while(0)
+
+static Glyph_Entry *
+_parse_glyph_entry(char **msg)
+{
+ Glyph_Entry *ge;
+ char *buf = *msg;
+
+ ge = calloc(1, sizeof(*ge));
+
+ READIT(ge->index, buf);
+ READIT(ge->offset, buf);
+ READIT(ge->size, buf);
+ READIT(ge->rows, buf);
+ READIT(ge->width, buf);
+ READIT(ge->pitch, buf);
+ READIT(ge->num_grays, buf);
+ READIT(ge->pixel_mode, buf);
+
+ *msg = buf;
+
+ return ge;
+}
+
+static Cache_Entry *
+_parse_cache_entry(char **msg)
+{
+ Cache_Entry *ce;
+ char *buf = *msg;
+ unsigned int n;
+
+ ce = calloc(1, sizeof(*ce));
+
+ READIT(n, buf);
+ ce->shmname = eina_stringshare_add_length(buf, n);
+ buf += n;
+
+ READIT(ce->size, buf);
+ READIT(ce->usage, buf);
+
+ READIT(n, buf);
+ while (n--)
+ {
+ Glyph_Entry *ge;
+ ge = _parse_glyph_entry(&buf);
+ ce->glyphs = eina_list_append(ce->glyphs, ge);
+ }
+
+ *msg = buf;
+
+ return ce;
+}
+
+static Font_Entry *
+_parse_font_entry(char **msg)
+{
+ Font_Entry *fe;
+ char *buf = *msg;
+ unsigned int n;
+
+ fe = calloc(1, sizeof(*fe));
+
+ READIT(n, buf);
+ if (n)
+ fe->file = eina_stringshare_add_length(buf, n);
+ buf += n;
+ READIT(n, buf);
+ if (n)
+ fe->name = eina_stringshare_add_length(buf, n);
+ buf += n;
+
+ READIT(fe->rend_flags, buf);
+ READIT(fe->size, buf);
+ READIT(fe->dpi, buf);
+ READIT(fe->unused, buf);
+
+ READIT(n, buf);
+ while (n--)
+ {
+ Cache_Entry *ce;
+ ce = _parse_cache_entry(&buf);
+ fe->caches = eina_list_append(fe->caches, ce);
+ }
+
+ *msg = buf;
+
+ return fe;
+}
+
+static Eina_List *
+_debug_msg_read(void)
+{
+ Msg_Base *msg = NULL;
+ char *buf;
+ int size;
+ unsigned int nfonts;
+ Eina_List *fonts = NULL;
+
+ printf("Requesting server debug info.\n\n");
+ while (!msg)
+ msg = _server_read(&size);
+
+ if (msg->type != CSERVE2_FONT_DEBUG)
+ {
+ ERR("Invalid message received from server."
+ "Something went badly wrong.");
+ return NULL;
+ }
+
+ buf = (char *)msg + sizeof(*msg);
+
+ READIT(nfonts, buf);
+ while (nfonts--)
+ {
+ Font_Entry *fe;
+ fe = _parse_font_entry(&buf);
+ fonts = eina_list_append(fonts, fe);
+ }
+
+ return fonts;
+}
+
+static void
+_glyph_entry_free(Glyph_Entry *ge)
+{
+ free(ge);
+}
+
+static void
+_cache_entry_free(Cache_Entry *ce)
+{
+ Glyph_Entry *ge;
+
+ EINA_LIST_FREE(ce->glyphs, ge)
+ _glyph_entry_free(ge);
+
+ eina_stringshare_del(ce->shmname);
+ free(ce);
+}
+
+static void
+_font_entry_free(Font_Entry *fe)
+{
+ Cache_Entry *ce;
+
+ EINA_LIST_FREE(fe->caches, ce)
+ _cache_entry_free(ce);
+
+ eina_stringshare_del(fe->name);
+ eina_stringshare_del(fe->file);
+ free(fe);
+}
+
+static void
+_glyph_entry_print(Glyph_Entry *ge)
+{
+ const char *pxmode[] = {
+ "FT_PIXEL_MODE_NONE",
+ "FT_PIXEL_MODE_MONO",
+ "FT_PIXEL_MODE_GRAY",
+ "FT_PIXEL_MODE_GRAY2",
+ "FT_PIXEL_MODE_GRAY4",
+ "FT_PIXEL_MODE_LCD",
+ "FT_PIXEL_MODE_LCD_V"
+ };
+ printf("\t\tGLYPH %u offset: %u size: %u %ux%u pitch: %u grays: %u "
+ "pixel mode: %s\n",
+ ge->index, ge->offset, ge->size, ge->width, ge->rows, ge->pitch,
+ ge->num_grays, pxmode[ge->pixel_mode]);
+}
+
+static void
+_cache_entry_print(Cache_Entry *ce)
+{
+ Eina_List *l;
+ Glyph_Entry *ge;
+
+ printf("\tSHM %s used %u/%u\n", ce->shmname, ce->usage, ce->size);
+
+ EINA_LIST_FOREACH(ce->glyphs, l, ge)
+ _glyph_entry_print(ge);
+}
+
+static void
+_font_entry_print(Font_Entry *fe)
+{
+ Eina_List *l;
+ Cache_Entry *ce;
+
+ printf("FONT %s:%s size: %u dpi: %u %s%s%s %s\n",
+ fe->file, fe->name, fe->size, fe->dpi,
+ fe->rend_flags == 0 ? "REGULAR " : "",
+ fe->rend_flags & 1 ? "SLANT " : "",
+ fe->rend_flags & 2 ? "WEIGHT" : "",
+ fe->unused ? "(unused)" : "");
+
+ EINA_LIST_FOREACH(fe->caches, l, ce)
+ _cache_entry_print(ce);
+
+ putchar('\n');
+}
+
+int
+main(void)
+{
+ Eina_List *fonts;
+ Font_Entry *fe;
+
+ eina_init();
+
+ _evas_cserve2_debug_log_dom = eina_log_domain_register
+ ("evas_cserve2_debug", EINA_COLOR_BLUE);
+
+ if (!_server_connect())
+ {
+ ERR("Could not connect to server.");
+ return -1;
+ }
+
+ _debug_msg_send();
+
+ fonts = _debug_msg_read();
+
+ EINA_LIST_FREE(fonts, fe)
+ {
+ _font_entry_print(fe);
+ _font_entry_free(fe);
+ }
+
+ _server_disconnect();
+
+ eina_shutdown();
+}
# include "config.h"
#endif
+#ifdef BUILD_FONT_LOADER_EET
+#include <Eet.h>
+#endif
+
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_SIZES_H
+#include FT_TYPES_H
#include FT_MODULE_H
+#include FT_OUTLINE_H
#include "evas_cserve2.h"
+#define CACHESIZE 4 * 1024
+
+/* The tangent of the slant angle we do on runtime. This value was
+ * retrieved from engines/common/evas_font.h */
+#define _EVAS_FONT_SLANT_TAN 0.221694663
+
+#define CHECK_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+#define MIN_GLYPHS 50
+#define MAX_CACHE_SIZE 1 * 1024 * 1024 // 1MB
+
+#define EVAS_FONT_ROUND_26_6_TO_INT(x) \
+ (((x + 0x20) & -0x40) >> 6)
+
static FT_Library cserve2_ft_lib = 0;
static int initialised = 0;
+typedef struct _Font_Info Font_Info;
+typedef struct _Font_Source_Info Font_Source_Info;
+
struct _Font_Info
{
+ Font_Source_Info *fsi;
FT_Size size;
- int real_size;
+ int real_size; // this is probably useless, not used even on client
+ int fsize;
+ int dpi;
int max_h;
unsigned int runtime_rend;
+ int shmsize;
};
struct _Font_Source_Info
FT_Face face;
int orig_upem;
int current_size;
+ int current_dpi;
+ void *data;
+ int datasize;
};
-typedef struct _Font_Info Font_Info;
-typedef struct _Font_Source_Info Font_Source_Info;
-
static void *
_font_slave_error_send(Error_Type error)
{
return e;
}
+static void
+_font_slave_size_use(Font_Info *fi)
+{
+ Font_Source_Info *fsi = fi->fsi;
+// if ((fsi->current_size != fi->fsize)
+// || (fsi->current_dpi != fi->dpi))
+ {
+ FT_Activate_Size(fi->size);
+ fsi->current_size = fi->fsize;
+ fsi->current_dpi = fi->dpi;
+ }
+}
+
static Font_Source_Info *
-_font_slave_source_load(const char *file)
+_font_slave_source_load(const char *file, const char *name)
{
int error;
- Font_Source_Info *fsi = malloc(sizeof(*fsi));
+ Font_Source_Info *fsi = calloc(1, sizeof(*fsi));
- error = FT_New_Face(cserve2_ft_lib, file, 0, &(fsi->face));
- if (error)
+ if (!name)
{
- free(fsi);
- return NULL;
+ error = FT_New_Face(cserve2_ft_lib, file, 0, &(fsi->face));
+ if (error)
+ {
+ free(fsi);
+ return NULL;
+ }
}
+#ifdef BUILD_FONT_LOADER_EET
+ else
+ {
+ Eet_File *ef;
+ void *fdata;
+ int fsize = 0;
+
+ ef = eet_open(file, EET_FILE_MODE_READ);
+ if (!ef)
+ {
+ free(fsi);
+ return NULL;
+ }
+ fdata = eet_read(ef, name, &fsize);
+ eet_close(ef);
+ if (!fdata)
+ {
+ free(fsi);
+ return NULL;
+ }
+ fsi->data = fdata;
+ fsi->datasize = fsize;
+
+ error = FT_New_Memory_Face(cserve2_ft_lib, fsi->data, fsi->datasize,
+ 0, &(fsi->face));
+ if (error)
+ {
+ free(fsi->data);
+ free(fsi);
+ return NULL;
+ }
+ }
+#endif
error = FT_Select_Charmap(fsi->face, ft_encoding_unicode);
if (error)
{
FT_Done_Face(fsi->face);
+ free(fsi->data);
free(fsi);
return NULL;
}
fsi->orig_upem = fsi->face->units_per_EM;
fsi->current_size = 0;
+ fsi->current_dpi = 0;
return fsi;
}
if (!error)
FT_Activate_Size(fi->size);
+ fi->fsize = msg->size;
+ fi->dpi = msg->dpi;
fi->real_size = msg->size * 64;
+ fi->fsi = fsi;
error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, msg->dpi, msg->dpi);
if (error)
- {
- fi->real_size = msg->size;
- error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size);
- }
+ error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size);
if (error)
{
- int i;
+ int i, maxd = 0x7fffffff;
int chosen_size = 0;
- int chosen_width = 0;
+ int chosen_size2 = 0;
for (i = 0; i < fsi->face->num_fixed_sizes; i++)
{
- int s;
- int d, cd;
+ int s, cd;
- s = fsi->face->available_sizes[i].height;
- cd = chosen_size - msg->size;
+ s = fsi->face->available_sizes[i].size;
+ cd = chosen_size - fi->real_size;
if (cd < 0) cd = -cd;
- d = s - msg->size;
- if (d < 0) d = -d;
- if (d < cd)
+ if (cd < maxd)
{
- chosen_width = fsi->face->available_sizes[i].width;
+ maxd = cd;
chosen_size = s;
+ chosen_size2 = fsi->face->available_sizes[i].y_ppem;
+ if (maxd == 0) break;
}
- if (d == 0) break;
}
fi->real_size = chosen_size;
- error = FT_Set_Pixel_Sizes(fsi->face, chosen_width, fi->real_size);
+ error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size);
if (error)
{
- ERR("Could not choose the font size for font: '%s'.", msg->name);
- FT_Done_Size(fi->size);
- free(fi);
- return NULL;
+ error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, fi->dpi, fi->dpi);
+ if (error)
+ {
+ /* hack around broken fonts */
+ fi->real_size = (chosen_size2 / 64) * 60;
+ error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, fi->dpi, fi->dpi);
+ if (error)
+ {
+ ERR("Could not choose the font size for font: '%s:%s'.",
+ msg->file, msg->name);
+ FT_Done_Size(fi->size);
+ free(fi);
+ return NULL;
+ }
+ }
}
}
Font_Source_Info *fsi;
Font_Info *fi;
+ DBG("slave received FONT_LOAD: '%s'", msg->name);
fsi = msg->ftdata1;
/* Loading Font Source */
if (!fsi)
- fsi = _font_slave_source_load(msg->file);
+ fsi = _font_slave_source_load(msg->file, msg->name);
// FIXME: Return correct error message
if (!fsi)
fi = _font_slave_int_load(msg, fsi);
if (!fi)
{
- FT_Done_Face(fsi->face);
- free(fsi);
+ if (!msg->ftdata1)
+ cserve2_font_source_ft_free(fsi);
return NULL;
}
return response;
}
+static Shm_Handle *
+_font_slave_memory_alloc(Font_Info *fi)
+{
+ Shm_Handle *shm = cserve2_shm_request(fi->shmsize);
+
+ return shm;
+}
+
+/* This function will load the "index" glyph to the glyph slot of the font.
+ * In order to use or render it, one should access it from the glyph slot,
+ * or get the glyph using FT_Get_Glyph().
+ */
+static Eina_Bool
+_font_slave_glyph_load(Font_Info *fi, unsigned int idx, unsigned int hint)
+{
+ Font_Source_Info *fsi = fi->fsi;
+ FT_Error error;
+ const FT_Int32 hintflags[3] =
+ { FT_LOAD_NO_HINTING, FT_LOAD_FORCE_AUTOHINT, FT_LOAD_NO_AUTOHINT };
+ static FT_Matrix transform = {0x10000, _EVAS_FONT_SLANT_TAN * 0x10000,
+ 0x00000, 0x10000};
+
+ error = FT_Load_Glyph(fsi->face, idx,
+ FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP |
+ hintflags[hint]);
+ if (error)
+ {
+ ERR("Could not load glyph %d", idx);
+ return EINA_FALSE;
+ }
+
+ /* Transform the outline of Glyph according to runtime_rend. */
+ if (fi->runtime_rend & FONT_REND_SLANT)
+ FT_Outline_Transform(&fsi->face->glyph->outline, &transform);
+ /* Embolden the outline of Glyph according to rundtime_rend. */
+ if (fi->runtime_rend & FONT_REND_WEIGHT)
+ FT_Outline_Embolden(&fsi->face->glyph->outline,
+ (fsi->face->size->metrics.x_ppem * 5 * 64) /
+ 100);
+
+ return EINA_TRUE;
+}
+
+/* This function will render the glyph currently in the glyph slot into the
+ * given Font Cache.
+ */
+static Eina_Bool
+_font_slave_glyph_render(Font_Info *fi, Slave_Msg_Font_Cache *c, unsigned int idx)
+{
+ Font_Source_Info *fsi = fi->fsi;
+ unsigned int glyphsize;
+ char *cachedata = cserve2_shm_map(c->shm);
+ FT_Glyph glyph;
+ FT_BitmapGlyph bglyph;
+
+ FT_Get_Glyph(fsi->face->glyph, &glyph);
+ FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
+ bglyph = (FT_BitmapGlyph)glyph;
+
+ glyphsize = bglyph->bitmap.pitch * bglyph->bitmap.rows;
+
+ if (c->usage + glyphsize > cserve2_shm_size_get(c->shm))
+ {
+ FT_Done_Glyph(glyph);
+ return EINA_FALSE;
+ }
+
+ memcpy(cachedata + c->usage, bglyph->bitmap.buffer, glyphsize);
+
+ // TODO: Check if we have problems with alignment
+ c->glyphs[c->nglyphs].index = idx;
+ c->glyphs[c->nglyphs].offset = c->usage;
+ c->glyphs[c->nglyphs].size = glyphsize;
+ c->glyphs[c->nglyphs].rows = bglyph->bitmap.rows;
+ c->glyphs[c->nglyphs].width = bglyph->bitmap.width;
+ c->glyphs[c->nglyphs].pitch = bglyph->bitmap.pitch;
+ c->glyphs[c->nglyphs].num_grays = bglyph->bitmap.num_grays;
+ c->glyphs[c->nglyphs].pixel_mode = bglyph->bitmap.pixel_mode;
+ c->usage += glyphsize;
+ c->nglyphs++;
+
+ FT_Done_Glyph(glyph);
+
+ return EINA_TRUE;
+}
+
+static void
+_font_slave_int_metrics_get(Font_Info *fi, unsigned int hint, unsigned int c, int *width, int *height, int *depth)
+{
+ unsigned int idx;
+ Font_Source_Info *fsi = fi->fsi;
+ FT_BBox outbox;
+ FT_Glyph glyph;
+
+ idx = FT_Get_Char_Index(fsi->face, c);
+ if (!idx)
+ goto end;
+
+ if (!_font_slave_glyph_load(fi, idx, hint))
+ goto end;
+
+ FT_Get_Glyph(fsi->face->glyph, &glyph);
+ FT_Glyph_Get_CBox(glyph,
+ ((hint == 0) ? FT_GLYPH_BBOX_UNSCALED :
+ FT_GLYPH_BBOX_GRIDFIT),
+ &outbox);
+ if (width) *width = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMax - outbox.xMin);
+ if (height)
+ *height = EVAS_FONT_ROUND_26_6_TO_INT(outbox.yMax - outbox.xMin);
+ if (depth) *depth = 1; // FIXME: Do we need to check this?
+ FT_Done_Glyph(glyph);
+ return;
+
+end:
+ if (width) *width = 0;
+ if (height) *height = 0;
+ if (depth) *depth = 0;
+}
+
+static unsigned int
+_font_slave_int_shm_prev_calculate(unsigned int size, unsigned int nglyphs)
+{
+ unsigned int average = size / nglyphs;
+ unsigned int newsize;
+
+ newsize = MIN_GLYPHS * average;
+ newsize = cserve2_shm_size_normalize(newsize);
+
+ if (newsize > MAX_CACHE_SIZE)
+ return MAX_CACHE_SIZE;
+
+ return newsize;
+}
+
+static unsigned int
+_font_slave_int_shm_calculate(Font_Info *fi, unsigned int hint)
+{
+ const char *c;
+ int i;
+ int size = 0;
+ int average;
+
+ for (c = CHECK_CHARS, i = 0; *c != '\0'; c++, i++)
+ {
+ int w, h, depth;
+ _font_slave_int_metrics_get(fi, hint, *c, &w, &h, &depth);
+ size += w * h * depth;
+ }
+
+ average = size / i; // average glyph size
+ size = MIN_GLYPHS * average;
+
+ size = cserve2_shm_size_normalize(size);
+
+ if (size > MAX_CACHE_SIZE)
+ return MAX_CACHE_SIZE; // Assumes no glyph will be bigger than this
+
+ return size;
+}
+
+static Slave_Msg_Font_Glyphs_Loaded *
+_font_slave_glyphs_load(const void *cmddata, void *data __UNUSED__)
+{
+ const Slave_Msg_Font_Glyphs_Load *msg = cmddata;
+ Slave_Msg_Font_Glyphs_Loaded *response;
+ Font_Info *fi;
+ unsigned int i;
+ unsigned int total_glyphs;
+ Eina_List *caches = NULL;
+ Slave_Msg_Font_Cache *c = NULL;
+
+ fi = msg->font.ftdata2;
+
+ _font_slave_size_use(fi);
+
+ if (msg->cache.shm)
+ {
+ c = malloc(sizeof(*c) + sizeof(Slave_Msg_Glyph) *
+ (msg->glyphs.nglyphs));
+ c->nglyphs = 0;
+ c->glyphs = (void *)(c + 1);
+ c->shm = msg->cache.shm;
+ c->usage = msg->cache.usage;
+ caches = eina_list_append(caches, c);
+ total_glyphs = msg->cache.nglyphs;
+ }
+
+ if (!fi->shmsize)
+ fi->shmsize = _font_slave_int_shm_calculate(fi, msg->font.hint);
+
+ i = 0;
+
+ while (i < msg->glyphs.nglyphs)
+ {
+ Eina_Bool r = EINA_TRUE;
+
+ if (!c)
+ {
+ Shm_Handle *shm;
+ shm = _font_slave_memory_alloc(fi);
+ c = malloc(sizeof(*c) + sizeof(Slave_Msg_Glyph) *
+ (msg->glyphs.nglyphs - i));
+ c->nglyphs = 0;
+ c->glyphs = (void *)(c + 1);
+ c->shm = shm;
+ c->usage = 0;
+ caches = eina_list_append(caches, c);
+ total_glyphs = 0;
+ }
+
+ if (_font_slave_glyph_load(fi, msg->glyphs.glyphs[i], msg->font.hint))
+ r = _font_slave_glyph_render(fi, c, msg->glyphs.glyphs[i]);
+ if (!r) // SHM is full
+ {
+ fi->shmsize = _font_slave_int_shm_prev_calculate
+ (c->usage, total_glyphs);
+ c = NULL;
+ continue;
+ }
+ i++;
+ total_glyphs++;
+ }
+
+ response = malloc(sizeof(*response) +
+ sizeof(c) * eina_list_count(caches));
+ response->ncaches = eina_list_count(caches);
+ response->caches = (void *)(response + 1);
+
+ i = 0;
+ EINA_LIST_FREE(caches, c)
+ response->caches[i++] = c;
+
+ return response;
+}
+
void *
cserve2_font_slave_cb(Slave_Thread_Data *sd __UNUSED__, Slave_Command *cmd, const void *cmddata, void *data)
{
response = _font_slave_load(cmddata, data);
break;
case FONT_GLYPHS_LOAD:
- // command for FONT_GLYPHS_LOAD
+ response = _font_slave_glyphs_load(cmddata, data);
break;
default:
ERR("Invalid command for font slave: %d", *cmd);
error = FT_Init_FreeType(&cserve2_ft_lib);
if (error) return;
+
+#ifdef BUILD_FONT_LOADER_EET
+ eet_init();
+#endif
}
void
FT_Done_FreeType(cserve2_ft_lib);
cserve2_ft_lib = 0;
+
+#ifdef BUILD_FONT_LOADER_EET
+ eet_shutdown();
+#endif
+}
+
+void
+cserve2_font_source_ft_free(void *fontsource)
+{
+ Font_Source_Info *fsi = fontsource;
+
+ FT_Done_Face(fsi->face);
+ free(fsi->data);
+ free(fsi);
+}
+
+void
+cserve2_font_ft_free(void *fontinfo)
+{
+ Font_Info *fi = fontinfo;
+
+ FT_Done_Size(fi->size);
+ free(fi);
}
static Eina_Inlist *slaves_idle = NULL;
static Eina_Inlist *slaves_working = NULL;
-struct _Glyph_Request {
- unsigned int index;
- unsigned int offset;
-};
-
-typedef struct _Glyph_Request Glyph_Request;
-
void
cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
{
EINA_INLIST_GET(sw));
sw->data = data;
+ sw->done = EINA_FALSE;
DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
cserve2_slave_send(sw->slave, cmd, msg, size);
return EINA_TRUE;
_cserve2_client_font_load(Client *client)
{
Msg_Font_Load *msg = (Msg_Font_Load *)client->msg.buf;
- char name[PATH_MAX];
+ char name[PATH_MAX], source[PATH_MAX], *buf;
- memcpy(name, msg + 1, msg->pathlen);
+ buf = ((char *)msg) + sizeof(*msg);
+ memcpy(source, buf, msg->sourcelen);
+ buf += msg->sourcelen;
+ memcpy(name, buf, msg->pathlen);
INF("Received %s command: RID=%d",
(msg->base.type == CSERVE2_FONT_LOAD) ? "FONT_LOAD" : "FONT_UNLOAD",
msg->base.rid);
- INF("Font: %s, rend_flags: %d, hint: %d, size: %d, dpi: %d",
- name, msg->rend_flags, msg->hint, msg->size, msg->dpi);
+ INF("Font: %s, rend_flags: %d, size: %d, dpi: %d",
+ name, msg->rend_flags, msg->size, msg->dpi);
- cserve2_cache_font_load(client, name, msg->pathlen, msg->rend_flags,
- msg->hint, msg->size, msg->dpi, msg->base.rid);
+ if (msg->base.type == CSERVE2_FONT_LOAD)
+ cserve2_cache_font_load(client, source, msg->sourcelen, name,
+ msg->pathlen, msg->rend_flags, msg->size,
+ msg->dpi, msg->base.rid);
+ else
+ cserve2_cache_font_unload(client, source, msg->sourcelen, name,
+ msg->pathlen, msg->rend_flags, msg->size,
+ msg->dpi, msg->base.rid);
}
static void
_cserve2_client_font_glyphs_request(Client *client)
{
Msg_Font_Glyphs_Request *msg = (Msg_Font_Glyphs_Request *)client->msg.buf;
- char fontpath[PATH_MAX];
- Glyph_Request *glyphs;
- unsigned int i;
- const char *bufpos = client->msg.buf;
+ char source[PATH_MAX], fontpath[PATH_MAX], *buf;
+ unsigned int *glyphs;
- memcpy(fontpath, msg + 1, msg->pathlen);
+ buf = ((char *)msg) + sizeof(*msg);
+ memcpy(source, buf, msg->sourcelen);
+ buf += msg->sourcelen;
+ memcpy(fontpath, buf, msg->pathlen);
+ buf += msg->pathlen;
- bufpos = bufpos + sizeof(msg) + msg->pathlen;
glyphs = malloc(sizeof(*glyphs) * msg->nglyphs);
-
- for (i = 0; i < msg->nglyphs; i++)
- {
- memcpy(&glyphs[i], bufpos, sizeof(*glyphs));
- bufpos += sizeof(*glyphs);
- }
+ memcpy(glyphs, buf, sizeof(*glyphs) * msg->nglyphs);
if (msg->base.type == CSERVE2_FONT_GLYPHS_LOAD)
{
INF("Received CSERVE2_FONT_GLYPHS_LOAD command: RID=%d",
msg->base.rid);
+ cserve2_cache_font_glyphs_load(client, source, msg->sourcelen,
+ fontpath, msg->pathlen,
+ msg->hint, msg->rend_flags, msg->size,
+ msg->dpi, glyphs, msg->nglyphs,
+ msg->base.rid);
}
else
{
INF("Received CSERVE2_FONT_GLYPHS_USED command: RID=%d",
msg->base.rid);
+ cserve2_cache_font_glyphs_used(client, source, msg->sourcelen,
+ fontpath, msg->pathlen,
+ msg->hint, msg->rend_flags, msg->size,
+ msg->dpi, glyphs, msg->nglyphs,
+ msg->base.rid);
}
}
+static void
+_cserve2_client_stats_request(Client *client)
+{
+ Msg_Base *msg = (Msg_Base *)client->msg.buf;
+ cserve2_cache_stats_get(client, msg->rid);
+}
+
+static void
+_cserve2_client_font_debug_request(Client *client)
+{
+ Msg_Base *msg = (Msg_Base *)client->msg.buf;
+ cserve2_cache_font_debug(client, msg->rid);
+}
+
void
cserve2_command_run(Client *client, Message_Type type)
{
case CSERVE2_FONT_GLYPHS_USED:
_cserve2_client_font_glyphs_request(client);
break;
+ case CSERVE2_STATS:
+ _cserve2_client_stats_request(client);
+ break;
+ case CSERVE2_FONT_DEBUG:
+ _cserve2_client_font_debug_request(client);
+ break;
default:
WRN("Unhandled message");
}
Fd_Flags flags;
Fd_Watch_Cb callback;
const void *user_data;
+ Eina_Bool deleted : 1;
};
typedef struct _Watch_Data Watch_Data;
static int inotify_fd = -1;
static struct sockaddr_un socket_local;
static Eina_Hash *watch_list;
+static Eina_List *deleted_watch_list;
static Eina_Hash *inotify_path_hash;
static Eina_Hash *inotify_id_hash;
static Eina_Bool running;
static void
_watch_data_free_cb(void *data)
{
- free(data);
+ Watch_Data *wd = data;
+ wd->deleted = EINA_TRUE;
+ deleted_watch_list = eina_list_append(deleted_watch_list, wd);
}
Eina_Bool
void
cserve2_main_loop_finish(void)
{
+ Watch_Data *wd;
+
_socketfd_finish();
_signalfd_finish();
_inotifyfd_finish();
eina_hash_free(watch_list);
+ EINA_LIST_FREE(deleted_watch_list, wd)
+ free(wd);
close(epoll_fd);
}
{
struct epoll_event events[MAX_EPOLL_EVENTS];
int n, nfds;
+ Watch_Data *data;
if (terminate)
break;
for (n = 0; n < nfds; n++)
{
- Watch_Data *data = events[n].data.ptr;
+ data = events[n].data.ptr;
Fd_Flags flags = 0;
if (!data)
continue;
+ if (data->deleted)
+ continue;
+
if (!data->callback)
continue;
data->callback(data->fd, flags, (void *)data->user_data);
}
+ EINA_LIST_FREE(deleted_watch_list, data)
+ free(data);
+
_update_timeout();
}
{
{ CSERVE2_REQ_FONT_LOAD, SLAVE_FONT, FONT_LOAD },
{ CSERVE2_REQ_FONT_GLYPHS_LOAD, SLAVE_FONT, FONT_GLYPHS_LOAD },
- { CSERVE2_REQ_LAST, 0 }
+ { CSERVE2_REQ_LAST, 0, 0 }
};
static Slave *_create_image_slave(void *data);
struct _Request_Queue
{
Eina_Inlist *waiting;
- Eina_Inlist *processing;
+ Eina_Inlist *processing; // TODO: Check if is there any use for this list.
};
typedef struct _Request_Queue Request_Queue;
static Request_Queue *requests = NULL;
// static Eina_List *processing = NULL;
+static void _cserve2_requests_process(void);
+
static void
_request_waiter_add(Font_Request *req, Client *client, unsigned int rid)
{
}
Font_Request *
-cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Font_Request_Funcs *funcs, void *data)
+cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Font_Request_Funcs *funcs __UNUSED__, void *data)
{
Font_Request *req, *r;
req = NULL;
+ /* Check if this request was already being processed. */
EINA_INLIST_FOREACH(requests[type].processing, r)
{
- if (r->data == data)
+ if (r->data != data)
continue;
req = r;
break;
}
+ /* Check if this request was already waiting to be processed. */
if (!req)
{
EINA_INLIST_FOREACH(requests[type].waiting, r)
}
}
+ /* create new request */
if (!req)
{
DBG("Add request for rid: %d", rid);
req = malloc(sizeof(*req));
+ req->type = type;
req->data = data;
req->waiters = NULL;
req->processing = EINA_FALSE;
+ req->funcs = funcs;
requests[type].waiting = eina_inlist_append(requests[type].waiting,
EINA_INLIST_GET(req));
}
_request_waiter_add(req, client, rid);
+ _cserve2_requests_process();
+
return req;
}
void
+cserve2_request_waiter_add(Font_Request *req, unsigned int rid, Client *client)
+{
+ _request_waiter_add(req, client, rid);
+}
+
+void
cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err)
{
Eina_List *l, *l_next;
// TODO: When we have speculative preload, there may be no waiters,
// so we need a flag or something else to make things still load.
- if (!req->waiters)
+ if ((!req->waiters) && (!req->processing))
{
Eina_Inlist **reqlist = &requests[req->type].waiting;
*reqlist = eina_inlist_remove(*reqlist, EINA_INLIST_GET(req));
// TODO: If the request is being processed, it can't be deleted. Must
// be marked as delete_me instead.
- req->funcs->msg_free(req->msg);
+ req->funcs->msg_free(req->msg, req->data);
free(req);
}
free(w);
}
+ if (req->processing)
+ return;
+
requests[req->type].waiting = eina_inlist_remove(
requests[req->type].waiting, EINA_INLIST_GET(req));
- req->funcs->msg_free(req->msg);
+ req->funcs->msg_free(req->msg, req->data);
free(req);
}
free(w);
}
- req->funcs->msg_free(req->msg);
+ req->funcs->msg_free(req->msg, req->data);
requests[req->type].processing = eina_inlist_remove(
requests[req->type].processing, EINA_INLIST_GET(req));
free(req);
free(w);
}
- req->funcs->msg_free(req->msg);
+ req->funcs->msg_free(req->msg, req->data);
// FIXME: We shouldn't free this message directly, it must be freed by a
// callback.
free(msg);
idle = &_workers[sw->type].idle;
*working = eina_list_remove(*working, sw);
*idle = eina_list_append(*idle, sw);
+
+ _cserve2_requests_process();
}
static void
int size;
char *slave_msg = req->funcs->msg_create(req->data, &size);
+
+ DBG("dispatching message of type %d to slave.", req->type);
if (!slave_msg)
{
ERR("Could not create slave message for request type %d.", req->type);
return EINA_TRUE;
}
-void
-cserve2_requests_process(void)
+static void
+_cserve2_requests_process(void)
{
- int rtype, j;
+ unsigned int rtype, j;
for (rtype = 0; rtype < CSERVE2_REQ_LAST; rtype++)
{
for (j = 0; _request_match[j].rtype != CSERVE2_REQ_LAST; j++)
{
- if (_request_match[j].rtype == j)
+ if (_request_match[j].rtype == rtype)
{
type = _request_match[j].stype;
ctype = _request_match[j].ctype;
idle = &_workers[type].idle;
working = &_workers[type].working;
- while (requests[j].waiting &&
+ while (requests[rtype].waiting &&
(eina_list_count(*working) < max_workers))
{
Slave_Worker *sw;
off_t image_offset;
size_t map_size;
size_t image_size;
+ int refcount;
+ void *data;
};
static int id = 0;
+size_t
+cserve2_shm_size_normalize(size_t size)
+{
+ long pagesize;
+ size_t normalized;
+
+ pagesize = sysconf(_SC_PAGESIZE);
+ if (pagesize < 1)
+ {
+ ERR("sysconf() reported weird value for PAGESIZE, assuming 4096.");
+ pagesize = 4096;
+ }
+
+ normalized = ((size + pagesize - 1) / pagesize) * pagesize;
+
+ return normalized;
+}
+
Shm_Handle *
cserve2_shm_request(size_t size)
{
Shm_Handle *shm;
char shmname[NAME_MAX];
size_t map_size;
- long pagesize;
int fd;
map = calloc(1, sizeof(Shm_Mapping));
}
} 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;
+ map_size = cserve2_shm_size_normalize(size);
if (ftruncate(fd, map_size) == -1)
{
Shm_Mapping *map = shm->mapping;
map->segments = eina_inlist_remove(map->segments, EINA_INLIST_GET(shm));
+
+ if (shm->data)
+ munmap(shm->data, shm->image_size);
free(shm);
if (map->segments)
{
return shm->image_size;
}
+
+void *
+cserve2_shm_map(Shm_Handle *shm)
+{
+ int fd;
+ const char *name;
+
+ if (shm->refcount++)
+ return shm->data;
+
+ name = cserve2_shm_name_get(shm);
+
+ fd = shm_open(name, O_RDWR, S_IWUSR);
+ if (fd == -1)
+ return MAP_FAILED;
+
+ shm->data = mmap(NULL, shm->image_size, PROT_WRITE, MAP_SHARED,
+ fd, shm->image_offset);
+
+ close(fd);
+
+ return shm->data;
+}
+
+void
+cserve2_shm_unmap(Shm_Handle *shm)
+{
+ if (--shm->refcount)
+ return;
+
+ munmap(shm->data, shm->image_size);
+ shm->data = NULL;
+}
return response_send(fd, ERROR, &err, sizeof(Error_Type));
}
-void *
-cserve2_shm_map(const char *name, size_t length, off_t offset)
+static void *
+_cserve2_shm_map(const char *name, size_t length, off_t offset)
{
void *map;
int fd;
return map;
}
-void
-cserve2_shm_unmap(void *map, size_t length)
+static void
+_cserve2_shm_unmap(void *map, size_t length)
{
munmap(map, length);
}
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);
+ char *map = _cserve2_shm_map(shmfile, params->shm.mmap_size,
+ params->shm.mmap_offset);
if (map == MAP_FAILED)
return CSERVE2_RESOURCE_ALLOCATION_FAILED;
result->alpha_sparse = ilp.alpha_sparse;
done:
- cserve2_shm_unmap(map, params->shm.mmap_size);
+ _cserve2_shm_unmap(map, params->shm.mmap_size);
return ret;
}
if (n != sizeof(cmd))
{
- ERR("Slave thread read invalid size of command from server: %d",
+ ERR("Slave thread read invalid size of command from server: %zu",
n);
continue;
}
--- /dev/null
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <Eina.h>
+
+#include "evas_cs2.h"
+
+static int socketfd = -1;
+static unsigned int _rid_count = 1;
+static int _evas_cserve2_usage_log_dom = -1;
+
+static struct sockaddr_un socksize;
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX sizeof(socksize.sun_path)
+#endif
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_usage_log_dom, __VA_ARGS__)
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_usage_log_dom, __VA_ARGS__)
+#ifdef WRN
+#undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_usage_log_dom, __VA_ARGS__)
+#ifdef INF
+#undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_usage_log_dom, __VA_ARGS__)
+
+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;
+ }
+
+ snprintf(buf, sizeof(buf), "/tmp/.evas-cserve2-%x.socket", (int)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 Eina_Bool
+_server_send(const void *data, int size)
+{
+ int sent = 0;
+ ssize_t ret;
+ const char *msg = data;
+
+ while (sent < size)
+ {
+ ret = send(socketfd, msg + sent, size - sent, MSG_NOSIGNAL);
+ if (ret < 0)
+ {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ return EINA_FALSE;
+ }
+ sent += ret;
+ }
+
+ 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;
+}
+
+static void
+_usage_msg_send(void)
+{
+ Msg_Base msg;
+ int size;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.type = CSERVE2_STATS;
+ msg.rid = _rid_count++;
+
+ size = sizeof(msg);
+
+ if (!_server_send(&size, sizeof(size)))
+ {
+ ERR("Could not send usage msg size to server.");
+ return;
+ }
+ if (!_server_send(&msg, size))
+ {
+ ERR("Could not send usage msg body to server.");
+ return;
+ }
+}
+
+static void
+_usage_msg_read(void)
+{
+ Msg_Stats *msg = NULL;
+ int size;
+
+ printf("Requesting server statistics.\n\n");
+ while (!msg)
+ msg = _server_read(&size);
+
+ if (msg->base.type != CSERVE2_STATS)
+ {
+ ERR("Invalid message received from server."
+ "Something went badly wrong.");
+ return;
+ }
+
+ printf("Printing server usage.\n");
+ printf("======================\n\n");
+ printf("\nImage Usage Statistics:\n");
+ printf("----------------------\n\n");
+ printf("Image headers usage: %d bytes\n", msg->images.files_size);
+ printf("Image data requested: %d kbytes\n", msg->images.requested_size / 1024);
+ printf("Image data usage: %d kbytes\n", msg->images.images_size / 1024);
+ printf("Image data unused: %d kbytes\n", msg->images.unused_size / 1024);
+ printf("Image headers load time: %dus\n", msg->images.files_load_time);
+ printf("Image headers saved time: %dus\n", msg->images.files_saved_time);
+ printf("Image data load time: %dus\n", msg->images.images_load_time);
+ printf("Image data saved time: %dus\n", msg->images.images_saved_time);
+ printf("\nFont Usage Statistics:\n");
+ printf("----------------------\n\n");
+ printf("Requested usage: %d bytes\n", msg->fonts.requested_size);
+ printf("Real usage: %d bytes\n", msg->fonts.real_size);
+ printf("Unused size: %d bytes\n", msg->fonts.unused_size);
+ printf("Fonts load time: %dus\n", msg->fonts.fonts_load_time);
+ printf("Fonts used load time: %dus\n", msg->fonts.fonts_used_load_time);
+ printf("Fonts used saved time: %dus\n", msg->fonts.fonts_used_saved_time);
+ printf("Glyphs load time: %dus\n", msg->fonts.glyphs_load_time);
+ printf("Glyphs saved time: %dus\n", msg->fonts.glyphs_saved_time);
+
+ printf("\n");
+}
+
+int
+main(void)
+{
+ eina_init();
+
+ _evas_cserve2_usage_log_dom = eina_log_domain_register
+ ("evas_cserve2_usage", EINA_COLOR_BLUE);
+
+ if (!_server_connect())
+ {
+ ERR("Could not connect to server.");
+ return -1;
+ }
+
+ _usage_msg_send();
+
+ _usage_msg_read();
+
+ _server_disconnect();
+
+ eina_shutdown();
+}
unsigned short strikethrough : 1; /**< whether the character is strikethrough'ed */
unsigned short fg_extended : 1; /**< whether the extended palette is used for the foreground color */
unsigned short bg_extended : 1; /**< whether the extended palette is used for the background color */
+ unsigned short double_width : 1; /**< if the codepoint is merged with the following cell to the right visually (cells must be in pairs with 2nd cell being a duplicate in all ways except codepoint is 0) */
};
/**
SUBDIRS += ../modules/engines/software_16/
EVAS_STATIC_MODULE += ../modules/engines/software_16/libevas_engine_software_16.la
endif
-if EVAS_STATIC_BUILD_SOFTWARE_16_DDRAW
-SUBDIRS += ../modules/engines/software_16_ddraw/
-EVAS_STATIC_MODULE += ../modules/engines/software_16_ddraw/libevas_engine_software_16_ddraw.la
-EVAS_STATIC_LIBADD += @evas_engine_software_16_ddraw_libs@
-endif
if EVAS_STATIC_BUILD_SOFTWARE_16_WINCE
SUBDIRS += ../modules/engines/software_16_wince/
EVAS_STATIC_MODULE += ../modules/engines/software_16_wince/libevas_engine_software_16_wince.la
fdata = eet_read(ef, nm, &fsize);
if ((fdata) && (fsize > 0))
{
- font = evas->engine.func->font_memory_load(evas->engine.data.output, fake_name, size, fdata, fsize, wanted_rend);
+ font = evas->engine.func->font_memory_load(evas->engine.data.output, source, nm, size, fdata, fsize, wanted_rend);
free(fdata);
}
eet_close(ef);
fdata = eet_read(ef, nm, &fsize);
if ((fdata) && (fsize > 0))
{
- ok = evas->engine.func->font_memory_add(evas->engine.data.output, font, fake_name, size, fdata, fsize, wanted_rend);
+ ok = evas->engine.func->font_memory_add(evas->engine.data.output, font, source, nm, size, fdata, fsize, wanted_rend);
free(fdata);
}
eet_close(ef);
if (n1 == n2)
{
- Evas_Object_Textblock_Node_Format *remove_format = NULL;
- Evas_Object_Textblock_Node_Text *merge_node = NULL;
if ((cur1->pos == 0) &&
(cur2->pos == eina_ustrbuf_length_get(n1->unicode)))
{
else
{
n = _NODE_TEXT(EINA_INLIST_GET(n1)->prev);
- if (n)
- {
- merge_node = n;
- remove_format = merge_node->format_node;
- }
- else
+ /* Short path */
+ if (!n)
{
/* Clear the whole textblock - do it nicer. */
evas_object_textblock_text_markup_set(cur1->obj, "");
}
eina_ustrbuf_remove(n1->unicode, cur1->pos, cur2->pos);
_evas_textblock_cursors_update_offset(cur1, cur1->node, cur1->pos, - (cur2->pos - cur1->pos));
- if (merge_node)
- {
- _evas_textblock_node_text_adjust_offsets_to_start(o, n1,
- 0, -1);
- _evas_textblock_nodes_merge(o, merge_node);
- evas_textblock_cursor_set_at_format(cur1, remove_format);
- }
}
else
{
cur->pos = 0;
}
+
+ /* Force recreation of everything for textblock.
+ * FIXME: We have the same thing in other places, merge it... */
+ evas_textblock_cursor_paragraph_first(o->cursor);
+ evas_textblock_cursor_text_append(o->cursor, "");
+
_evas_textblock_changed(o, obj);
}
typedef struct _Evas_Object_Textgrid_Rect Evas_Object_Textgrid_Rect;
typedef struct _Evas_Object_Textgrid_Text Evas_Object_Textgrid_Text;
typedef struct _Evas_Object_Textgrid_Line Evas_Object_Textgrid_Line;
+typedef struct _Evas_Textgrid_Hash_Master Evas_Textgrid_Hash_Master;
+typedef struct _Evas_Textgrid_Hash_Glyphs Evas_Textgrid_Hash_Glyphs;
+
+struct _Evas_Textgrid_Hash_Master
+{
+ int next[16];
+};
+
+struct _Evas_Textgrid_Hash_Glyphs
+{
+ Evas_Text_Props props[256];
+};
struct _Evas_Object_Textgrid
{
Evas_Font_Size font_size;
Evas_Font_Description *font_description;
- Eina_Array *palette_standard;
- Eina_Array *palette_extended;
+ Eina_Array palette_standard;
+ Eina_Array palette_extended;
} cur, prev;
int max_ascent;
Evas_Font_Set *font;
+ Evas_Textgrid_Hash_Master *master;
+ Evas_Textgrid_Hash_Glyphs *glyphs;
+ unsigned char *master_used;
+ unsigned char *glyphs_used;
+ unsigned int master_length;
+ unsigned int glyphs_length;
+
+ unsigned int last_mask;
+ Evas_Textgrid_Hash_Glyphs *last_glyphs;
+
+ Eina_Array glyphs_cleanup;
+
unsigned int changed : 1;
unsigned int core_change : 1;
unsigned int row_change : 1;
{
unsigned char r, g, b, a;
int x;
- Evas_Text_Props text_props;
+ unsigned int text_props;
};
struct _Evas_Object_Textgrid_Line
EVAS_MEMPOOL(_mp_obj);
+/* almost generic private array data type */
+static int
+evas_object_textgrid_textprop_get(Evas_Object *obj, Evas_Object_Textgrid *o, Eina_Unicode codepoint,
+ unsigned int glyphs_index, unsigned char *used)
+{
+ Evas_Textgrid_Hash_Glyphs *glyph;
+ unsigned char idx = codepoint & 0xFF;
+
+ glyph = &(o->glyphs[glyphs_index]);
+
+ if (!glyph->props[idx].info)
+ {
+ Evas_Font_Instance *script_fi = NULL;
+ Evas_Font_Instance *cur_fi = NULL;
+ Evas_Script_Type script;
+
+ script = evas_common_language_script_type_get(&codepoint, 1);
+ ENFN->font_run_end_get(ENDT, o->font, &script_fi, &cur_fi, script, &codepoint, 1);
+ memset(&(glyph->props[idx]), 0, sizeof(Evas_Text_Props));
+ evas_common_text_props_script_set(&(glyph->props[idx]), script);
+ ENFN->font_text_props_info_create(ENDT, script_fi, &codepoint,
+ &(glyph->props[idx]), NULL, 0, 1,
+ EVAS_TEXT_PROPS_MODE_NONE);
+ (*used)++;
+ }
+ else
+ {
+ evas_common_text_props_content_ref(&(glyph->props[idx]));
+ }
+
+ return glyphs_index << 8 | (unsigned int) idx;
+}
+
+static int
+evas_object_textgrid_textprop_ref(Evas_Object *obj, Evas_Object_Textgrid *o, Eina_Unicode codepoint)
+{
+ unsigned int mask = 0xF0000000;
+ unsigned int shift = 28;
+ unsigned int offset = 0;
+ unsigned int glyphs_index;
+
+ if (o->last_glyphs)
+ {
+ if (o->last_mask && (o->last_mask & codepoint) == o->last_mask)
+ goto end;
+ }
+
+ if (!o->master)
+ {
+ o->master = calloc(6, sizeof (Evas_Textgrid_Hash_Master));
+ o->master_used = calloc(6, sizeof (unsigned char));
+ o->glyphs = calloc(1, sizeof (Evas_Textgrid_Hash_Glyphs));
+ o->glyphs_used = calloc(1, sizeof (unsigned char));
+ if (!o->master_used)
+ {
+ free(o->master);
+ o->master = NULL;
+ free(o->master_used);
+ o->master_used = NULL;
+ free(o->glyphs);
+ o->glyphs = NULL;
+ free(o->glyphs_used);
+ o->glyphs_used = NULL;
+ return 0xFFFFFFFF;
+ }
+
+ while (shift > 8)
+ {
+ o->master[offset].next[(mask & codepoint) >> shift] = offset + 1;
+ o->master_used[offset] = 1;
+ offset++;
+ shift -= 4;
+ mask >>= 4;
+ }
+
+ o->glyphs_length = 1;
+ o->master_length = 6;
+ o->master[5].next[(codepoint & 0xF00) >> 8] = 0xFF000000;
+ o->last_glyphs = o->glyphs;
+ o->last_mask = codepoint & 0xFFFFFF00;
+
+ goto end;
+ }
+
+ while (shift > 8
+ && o->master[offset].next[(codepoint & mask) >> shift] != 0)
+ {
+ offset = o->master[offset].next[(codepoint & mask) >> shift];
+ mask >>= 4;
+ shift -= 4;
+ }
+
+ if (shift > 8)
+ {
+ Evas_Textgrid_Hash_Master *tmp;
+ unsigned char *tmp_used;
+ int master_count;
+ int count;
+ int end;
+
+ count = (shift - 8) / 4;
+ master_count = o->master_length + count;
+
+ /* FIXME: find empty entry */
+ tmp = realloc(o->master, master_count * sizeof (Evas_Textgrid_Hash_Master));
+ if (!tmp) return 0xFFFFFFFF;
+ o->master = tmp;
+ tmp_used = realloc(o->master_used, master_count);
+ if (!tmp_used) return 0xFFFFFFFF;
+ o->master_used = tmp_used;
+
+ memset(o->master + o->master_length, 0, count * sizeof (Evas_Textgrid_Hash_Master));
+ memset(o->master_used + o->master_length, 1, count);
+ end = o->master_length;
+ o->master_length = master_count;
+
+ while (shift > 8)
+ {
+ o->master[offset].next[(mask & codepoint) >> shift] = end;
+ o->master_used[offset] = 1;
+ end++;
+ offset = end;
+ shift -= 4;
+ mask >>= 4;
+ }
+ offset--;
+ }
+ if (o->master[offset].next[(codepoint & mask) >> shift] == 0)
+ {
+ Evas_Textgrid_Hash_Glyphs *tmp;
+ unsigned char *tmp_used;
+ int count;
+
+ /* FIXME: find empty entry */
+ count = o->glyphs_length + 1;
+ tmp = realloc(o->glyphs, count * sizeof (Evas_Textgrid_Hash_Glyphs));
+ if (!tmp) return 0xFFFFFFFF;
+ o->glyphs = tmp;
+ tmp_used = realloc(o->glyphs_used, count * sizeof (unsigned char));
+ if (!tmp_used) return 0xFFFFFFFF;
+ o->glyphs_used = tmp_used;
+
+ o->master[offset].next[(codepoint & mask) >> shift] = o->glyphs_length + 0xFF000000;
+
+ memset(o->glyphs + o->glyphs_length, 0, sizeof (Evas_Textgrid_Hash_Glyphs));
+ o->glyphs_used[o->glyphs_length] = 0;
+ o->glyphs_length = count;
+ }
+
+ o->last_glyphs = o->glyphs + (o->master[offset].next[(codepoint & mask) >> shift] & 0xFFFFFF);
+ o->last_mask = codepoint & 0xFFFFFF00;
+
+ end:
+ glyphs_index = o->last_glyphs - o->glyphs;
+ return evas_object_textgrid_textprop_get(obj, o, codepoint, glyphs_index,
+ &(o->glyphs_used[glyphs_index]));
+}
+
+static void
+evas_object_textgrid_textprop_unref(Evas_Object_Textgrid *o, unsigned int props_index)
+{
+ Evas_Text_Props *props;
+
+ props = &(o->glyphs[props_index >> 8].props[props_index & 0xFF]);
+
+ if (props->info)
+ {
+ if (props->info->refcount == 1)
+ eina_array_push(&o->glyphs_cleanup, (intptr_t*)(int64_t) props_index);
+ else
+ evas_common_text_props_content_unref(props);
+ }
+}
+
+static Evas_Text_Props *
+evas_object_textgrid_textprop_int_to(Evas_Object_Textgrid *o, int props)
+{
+ return &(o->glyphs[props >> 8].props[props & 0xFF]);
+}
+
/* all nice and private */
static void
evas_object_textgrid_init(Evas_Object *obj)
EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Textgrid);
o->magic = MAGIC_OBJ_TEXTGRID;
o->prev = o->cur;
- o->cur.palette_standard = eina_array_new(16);
- o->cur.palette_extended = eina_array_new(16);
+ eina_array_step_set(&o->cur.palette_standard, sizeof (Eina_Array), 16);
+ eina_array_step_set(&o->cur.palette_extended, sizeof (Eina_Array), 16);
+ eina_array_step_set(&o->glyphs_cleanup, sizeof (Eina_Array), 16);
return o;
}
static void
-evas_object_textgrid_row_clear(Evas_Object_Textgrid_Row *r)
+evas_object_textgrid_row_clear(Evas_Object_Textgrid *o, Evas_Object_Textgrid_Row *r)
{
int i;
if (r->texts)
{
for (i = 0; i < r->texts_num; i++)
- evas_common_text_props_content_unref(&(r->texts[i].text_props));
+ if (r->texts[i].text_props != 0xFFFFFFFF)
+ {
+ evas_object_textgrid_textprop_unref(o, r->texts[i].text_props);
+ r->texts[i].text_props = 0xFFFFFFFF;
+ }
free(r->texts);
r->texts = NULL;
r->texts_num = 0;
if (!o->cur.rows) return;
for (i = 0; i < o->cur.h; i++)
{
- evas_object_textgrid_row_clear(&(o->cur.rows[i]));
+ evas_object_textgrid_row_clear(o, &(o->cur.rows[i]));
o->cur.rows[i].ch1 = 0;
o->cur.rows[i].ch2 = o->cur.w - 1;
}
static void
evas_object_textgrid_free(Evas_Object *obj)
{
+ Evas_Object_Textgrid_Color *c;
Evas_Object_Textgrid *o;
- unsigned int i;
/* frees private object data. very simple here */
o = (Evas_Object_Textgrid *)(obj->object_data);
if (o->cur.font_description) evas_font_desc_unref(o->cur.font_description);
if (o->font) evas_font_free(obj->layer->evas, o->font);
if (o->cur.cells) free(o->cur.cells);
- for (i = 0; i < eina_array_count(o->cur.palette_standard); i++)
- free(eina_array_data_get(o->cur.palette_standard, i));
- eina_array_free(o->cur.palette_standard);
- for (i = 0; i < eina_array_count(o->cur.palette_extended); i++)
- free(eina_array_data_get(o->cur.palette_extended, i));
- eina_array_free(o->cur.palette_extended);
+ while ((c = eina_array_pop(&o->cur.palette_standard)))
+ free(c);
+ eina_array_flush(&o->cur.palette_standard);
+ while ((c = eina_array_pop(&o->cur.palette_extended)))
+ free(c);
+ eina_array_flush(&o->cur.palette_extended);
+
+ while (eina_array_count(&o->glyphs_cleanup) > 0)
+ {
+ Evas_Text_Props *prop;
+ unsigned int props_index;
+
+ props_index = (unsigned int) (intptr_t) eina_array_pop(&o->glyphs_cleanup);
+ prop = &(o->glyphs[props_index >> 8].props[props_index & 0xFF]);
+
+ evas_common_text_props_content_unref(prop);
+ if (!prop->info)
+ {
+ o->glyphs_used[props_index >> 8]--;
+
+ if (!o->glyphs_used[props_index >> 8])
+ {
+ /* FIXME: cleanup the master tree */
+ }
+ }
+ }
+ eina_array_flush(&o->glyphs_cleanup);
+
+ free(o->master);
+ free(o->glyphs);
+ free(o->master_used);
+ free(o->glyphs_used);
+
o->magic = 0;
/* FIXME: using evas mempool like text ? */
EVAS_MEMPOOL_FREE(_mp_obj, o);
static void
evas_object_textgrid_row_text_append(Evas_Object_Textgrid_Row *row, Evas_Object *obj, Evas_Object_Textgrid *o, int x, Eina_Unicode codepoint, int r, int g, int b, int a)
{
- Evas_Script_Type script;
- Evas_Font_Instance *script_fi = NULL;
- Evas_Font_Instance *cur_fi = NULL;
-
row->texts_num++;
if (row->texts_num > row->texts_alloc)
{
}
row->texts = t;
}
-
- script = evas_common_language_script_type_get(&codepoint, 1);
- ENFN->font_run_end_get(ENDT, o->font, &script_fi, &cur_fi,
- script, &codepoint, 1);
- memset(&(row->texts[row->texts_num - 1].text_props), 0,
- sizeof(Evas_Text_Props));
- evas_common_text_props_script_set
- (&(row->texts[row->texts_num - 1].text_props), script);
- ENFN->font_text_props_info_create
- (ENDT, script_fi, &codepoint,
- &(row->texts[row->texts_num - 1].text_props), NULL, 0, 1,
- EVAS_TEXT_PROPS_MODE_NONE);
+
+ row->texts[row->texts_num - 1].text_props = evas_object_textgrid_textprop_ref(obj, o, codepoint);
row->texts[row->texts_num - 1].x = x;
row->texts[row->texts_num - 1].r = r;
row->texts[row->texts_num - 1].g = g;
row->ch1 = -1;
row->ch2 = 0;
run = 0;
- xp = obj->cur.geometry.x;
+ xp = 0;
for (xx = 0; xx < o->cur.w; xx++, cells++)
{
- if (cells->bg_extended) palette = o->cur.palette_extended;
- else palette = o->cur.palette_standard;
- c = eina_array_data_get(palette, cells->bg);
+ if (cells->bg_extended) palette = &(o->cur.palette_extended);
+ else palette = &(o->cur.palette_standard);
+ if (cells->bg >= eina_array_count(palette)) c = NULL;
+ else c = eina_array_data_get(palette, cells->bg);
if ((c) && (c->a > 0))
{
if (!run)
}
if (cells->codepoint > 0)
{
- if (cells->fg_extended) palette = o->cur.palette_extended;
- else palette = o->cur.palette_standard;
- c = eina_array_data_get(palette, cells->fg);
+ if (cells->fg_extended) palette = &(o->cur.palette_extended);
+ else palette = &(o->cur.palette_standard);
+ if (cells->fg >= eina_array_count(palette)) c = NULL;
+ else c = eina_array_data_get(palette, cells->fg);
if ((c) && (c->a > 0))
{
evas_object_textgrid_row_text_append(row, obj, o, xp,
// XXX: underlines and strikethroughs dont get
// merghed into horizontal runs like bg rects above
if (cells->underline)
- evas_object_textgrid_row_line_append(row, rx, rw,
+ evas_object_textgrid_row_line_append(row, xp, w,
o->max_ascent + 1,
- rr, rg, rb, ra);
+ c->r, c->g, c->b, c->a);
if (cells->strikethrough)
- evas_object_textgrid_row_line_append(row, rx, rw,
+ evas_object_textgrid_row_line_append(row, xp, w,
((3 * o->max_ascent) / 4),
- rr, rg, rb, ra);
+ c->r, c->g, c->b, c->a);
}
}
xp += w;
row->texts[xx].b, row->texts[xx].a);
ENFN->font_draw(output, context, surface, o->font,
xp + row->texts[xx].x, yp + o->max_ascent,
- ww, hh, ww, hh, &(row->texts[xx].text_props));
+ ww, hh, ww, hh,
+ evas_object_textgrid_textprop_int_to(o, row->texts[xx].text_props));
}
for (xx = 0; xx < row->lines_num; xx++)
{
row->lines[xx].b, row->lines[xx].a);
ENFN->rectangle_draw(output, context, surface,
xp + row->lines[xx].x, yp + row->lines[xx].y,
- row->lines[xx].w, h);
+ row->lines[xx].w, 1);
}
yp += h;
}
}
if (o->pal_change)
{
- unsigned int i;
-
- if (eina_array_count(o->cur.palette_standard) != eina_array_count(o->prev.palette_standard))
- {
- evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
- goto done;
- }
- for (i = 0; i < eina_array_count(o->cur.palette_standard); i++)
- {
- Evas_Object_Textgrid_Color *c_cur;
- Evas_Object_Textgrid_Color *c_prev;
-
- c_cur = eina_array_data_get(o->cur.palette_standard, i);
- c_prev = eina_array_data_get(o->prev.palette_standard, i);
- if ((c_cur->a != c_prev->a) ||
- (c_cur->r != c_prev->r) ||
- (c_cur->g != c_prev->g) ||
- (c_cur->b != c_prev->b))
- {
- evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
- goto done;
- }
- }
- if (eina_array_count(o->cur.palette_extended) != eina_array_count(o->prev.palette_extended))
- {
- evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
- goto done;
- }
- for (i = 0; i < eina_array_count(o->cur.palette_extended); i++)
- {
- Evas_Object_Textgrid_Color *c_cur;
- Evas_Object_Textgrid_Color *c_prev;
-
- c_cur = eina_array_data_get(o->cur.palette_extended, i);
- c_prev = eina_array_data_get(o->prev.palette_extended, i);
- if ((c_cur->a != c_prev->a) ||
- (c_cur->r != c_prev->r) ||
- (c_cur->g != c_prev->g) ||
- (c_cur->b != c_prev->b))
- {
- evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
- goto done;
- }
- }
+ evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
+ goto done;
}
if (o->row_change)
{
obj->prev = obj->cur;
o->prev = o->cur;
o->changed = 0;
+
+ while (eina_array_count(&o->glyphs_cleanup) > 0)
+ {
+ Evas_Text_Props *prop;
+ unsigned int props_index;
+
+ props_index = (unsigned int) (intptr_t) eina_array_pop(&o->glyphs_cleanup);
+ prop = &(o->glyphs[props_index >> 8].props[props_index & 0xFF]);
+
+ evas_common_text_props_content_unref(prop);
+ if (!prop->info)
+ {
+ o->glyphs_used[props_index >> 8]--;
+
+ if (!o->glyphs_used[props_index >> 8])
+ {
+ /* FIXME: cleanup the master tree */
+ }
+ }
+ }
}
static unsigned int
Evas_Font_Instance *cur_fi = NULL;
Evas_Text_Props text_props;
Evas_Script_Type script;
+ int advance, vadvance;
script = evas_common_language_script_type_get(W, 1);
ENFN->font_run_end_get(ENDT, o->font, &script_fi, &cur_fi,
ENFN->font_string_size_get(ENDT, o->font, &text_props,
&o->cur.char_width, &o->cur.char_height);
o->max_ascent = ENFN->font_max_ascent_get(ENDT, o->font);
+// inset = ENFN->font_inset_get(ENDT, o->font, &text_props);
+ advance = ENFN->font_h_advance_get(ENDT, o->font, &text_props);
+ vadvance = ENFN->font_v_advance_get(ENDT, o->font, &text_props);
+ if (advance > o->cur.char_width) o->cur.char_width = advance;
+ if (vadvance > o->cur.char_height) o->cur.char_height = vadvance;
evas_common_text_props_content_unref(&text_props);
}
else
o->core_change = 1;
evas_object_textgrid_rows_clear(obj);
evas_object_change(obj);
+
+ /* Force destroy of all cached Evas_Text_Props */
+ while (eina_array_count(&o->glyphs_cleanup) > 0)
+ {
+ Evas_Text_Props *prop;
+ unsigned int props_index;
+
+ props_index = (unsigned int) (intptr_t) eina_array_pop(&o->glyphs_cleanup);
+ prop = &(o->glyphs[props_index >> 8].props[props_index & 0xFF]);
+
+ evas_common_text_props_content_unref(prop);
+ if (!prop->info)
+ {
+ o->glyphs_used[props_index >> 8]--;
+
+ if (!o->glyphs_used[props_index >> 8])
+ {
+ /* FIXME: cleanup the master tree */
+ }
+ }
+ }
}
EAPI void
switch (pal)
{
case EVAS_TEXTGRID_PALETTE_STANDARD:
- palette = o->cur.palette_standard;
+ palette = &(o->cur.palette_standard);
break;
case EVAS_TEXTGRID_PALETTE_EXTENDED:
- palette = o->cur.palette_extended;
+ palette = &(o->cur.palette_extended);
break;
default:
return;
}
- color = malloc(sizeof(Evas_Object_Textgrid_Color));
- if (!color) return;
+ count = eina_array_count(palette);
+ if (idx < count)
+ {
+ color = eina_array_data_get(palette, idx);
+ if (color->a == a &&
+ color->r == r &&
+ color->g == g &&
+ color->b == b)
+ return ;
+ }
+ else
+ {
+ color = malloc(sizeof(Evas_Object_Textgrid_Color));
+ if (!color) return;
+ }
color->a = a;
color->r = r;
color->g = g;
color->b = b;
- count = eina_array_count(palette);
if (idx < count) eina_array_data_set(palette, idx, color);
else if (idx == count) eina_array_push(palette, color);
else
switch (pal)
{
case EVAS_TEXTGRID_PALETTE_STANDARD:
- palette = o->cur.palette_standard;
+ palette = &(o->cur.palette_standard);
break;
case EVAS_TEXTGRID_PALETTE_EXTENDED:
- palette = o->cur.palette_extended;
+ palette = &(o->cur.palette_extended);
break;
default:
return;
if (r->ch1 < 0)
{
- evas_object_textgrid_row_clear(r);
+ evas_object_textgrid_row_clear(o, r);
r->ch1 = x;
r->ch2 = x2;
}
if EVAS_CSERVE2
-noinst_LTLIBRARIES = libevas_cserve2.la
+noinst_LTLIBRARIES = libevas_cserve2.la libevas_cserve2_utils.la
libevas_cserve2_la_SOURCES = \
evas_cs2.h \
evas_cs2_image_data.c \
evas_cs2_client.c
-libevas_cserve2_la_LIBADD = @EINA_LIBS@
+libevas_cserve2_utils_la_SOURCES = \
+evas_cs2_utils.h \
+evas_cs2_utils.c
+
+libevas_cserve2_la_LIBADD = @EINA_LIBS@ libevas_cserve2_utils.la
endif
CSERVE2_FONT_GLYPHS_LOAD,
CSERVE2_FONT_GLYPHS_LOADED,
CSERVE2_FONT_GLYPHS_USED,
+ CSERVE2_STATS,
+ CSERVE2_FONT_DEBUG,
CSERVE2_ERROR
} Message_Type;
*/
struct _Msg_Font_Load {
Msg_Base base;
+ unsigned int sourcelen; // font id
unsigned int pathlen; // font id
unsigned int rend_flags; // font id
- unsigned int hint; // font id
unsigned int size; // font id
unsigned int dpi; // font id
};
/**
* @struct _Msg_Font_Glyphs_Request
*
- * Message from client to request load of glyphs, of inform usage of them.
+ * Message from client to request load of glyphs, or inform usage of them.
*
* The path strings follow the struct inside the message, as well as
* the list of glyphs to be loaded.
*/
struct _Msg_Font_Glyphs_Request {
Msg_Base base;
+ unsigned int sourcelen; // font id
unsigned int pathlen; // font id
unsigned int rend_flags; // font id
- unsigned int hint; // font id
unsigned int size; // font id
unsigned int dpi; // font id
+ unsigned int hint;
unsigned int nglyphs;
};
* - struct {
* unsigned int index;
* unsigned int offset;
+ * unsigned int size;
+ * unsigned int rows;
+ * unsigned int width;
+ * unsigned int pitch;
+ * unsigned int num_grays;
+ * unsigned int pixel_mode;
* } glarray[];
*/
struct _Msg_Font_Glyphs_Loaded {
unsigned int ncaches;
};
+struct _Msg_Stats {
+ Msg_Base base;
+ struct {
+ unsigned int requested_size;
+ unsigned int real_size;
+ unsigned int unused_size;
+ unsigned int fonts_loaded; /* number of loaded fonts */
+ unsigned int fonts_unused; /* number of loaded fonts without reference
+ * from any clients */
+ int fonts_load_time; /* total time spent loading fonts */
+ int fonts_used_load_time; /* total time spent loading fonts that are
+ * really used, i.e. fonts that have glyphs
+ * rendered */
+ int fonts_used_saved_time;
+ int glyphs_load_time; /* total time spent loading glyphs */
+ int glyphs_saved_time; /* total time spent loading glyphs */
+ } fonts;
+ struct {
+ unsigned int files_loaded; /* number of file headers loaded */
+ unsigned int images_loaded; /* number of image data loaded */
+ unsigned int images_unused; /* number of image data loaded and unused */
+
+ unsigned int requested_size; /* memory usage originally requested by
+ * the client */
+ unsigned int files_size; /* memory usage from image headers */
+ unsigned int images_size; /* memory usage from image data */
+ unsigned int unused_size; /* memory usage from image data */
+
+ int files_load_time;
+ int files_saved_time;
+ int images_load_time;
+ int images_saved_time;
+ } images;
+};
+
+/*
+ * @struct _Msg_Font_Debug
+ *
+ * Message from server containing all font cache info.
+ *
+ * Content of the message follows:
+ *
+ * * number of font entries;
+ * * each font entry:
+ * - unsigned int filelen
+ * - const char file
+ * - unsigned int namelen
+ * - const char name
+ * - unsigned int rend_flags;
+ * - unsigned int size;
+ * - unsigned int dpi;
+ * - unsigned int unused;
+ * - ncaches:
+ * - each cache:
+ * * usigned int shmnamelen;
+ * * const char shmname;
+ * * unsigned int size;
+ * * unsigned int usage;
+ * * unsigned int nglyphs;
+ * * each glyph:
+ * - unsigned int index;
+ * - unsigned int offset;
+ * - unsigned int size;
+ * - unsigned int rows;
+ * - unsigned int width;
+ * - unsigned int pitch;
+ * - unsigned int num_grays;
+ * - unsigned int pixel_mode;
+ */
+struct _Msg_Font_Debug {
+ Msg_Base base;
+};
+
struct _Msg_Error {
Msg_Base base;
int error;
typedef struct _Msg_Font_Loaded Msg_Font_Loaded;
typedef struct _Msg_Font_Glyphs_Request Msg_Font_Glyphs_Request;
typedef struct _Msg_Font_Glyphs_Loaded Msg_Font_Glyphs_Loaded;
+typedef struct _Msg_Stats Msg_Stats;
+typedef struct _Msg_Font_Debug Msg_Font_Debug;
typedef struct _Msg_Error Msg_Error;
#endif
#include "evas_cs2.h"
#include "evas_cs2_private.h"
+#include "evas_cs2_utils.h"
#ifdef EVAS_CSERVE2
}
static Eina_Bool
+_server_safe_send(int fd, const void *data, int size)
+{
+ int sent = 0;
+ ssize_t ret;
+ const char *msg = data;
+
+ while (sent < size)
+ {
+ ret = send(fd, msg + sent, size - sent, MSG_NOSIGNAL);
+ if (ret < 0)
+ {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ return EINA_FALSE;
+ }
+ sent += ret;
+ }
+
+ return EINA_TRUE;
+}
+
+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)
+ if (!_server_safe_send(socketfd, &size, sizeof(size)))
{
ERR("Couldn't send message size to server.");
return EINA_FALSE;
}
- if (send(socketfd, buf, size, MSG_NOSIGNAL) == -1)
+ if (!_server_safe_send(socketfd, buf, size))
{
ERR("Couldn't send message body to server.");
return EINA_FALSE;
case CSERVE2_SETOPTS:
case CSERVE2_LOAD:
case CSERVE2_PRELOAD:
+ case CSERVE2_FONT_LOAD:
+ case CSERVE2_FONT_GLYPHS_LOAD:
_request_answer_add(msg->type, msg->rid, cb, data);
break;
default:
{
_server_dispatch_until(0);
}
+
+typedef struct _Glyph_Map Glyph_Map;
+typedef struct _CS_Glyph_Out CS_Glyph_Out;
+
+struct _Font_Entry
+{
+ const char *source;
+ const char *name;
+ unsigned int size;
+ unsigned int dpi;
+ Font_Rend_Flags wanted_rend;
+
+ unsigned int rid; // open
+
+ Eina_Hash *glyphs_maps;
+ Fash_Glyph2 *fash[3]; // one per hinting value
+
+ Eina_Clist glyphs_queue;
+ int glyphs_queue_count;
+ Eina_Clist glyphs_used;
+ int glyphs_used_count;
+
+ Eina_Bool failed : 1;
+};
+
+struct _Glyph_Map
+{
+ Font_Entry *fe;
+ const char *name;
+ unsigned int size;
+ Eina_File *map;
+ unsigned char *data;
+ Eina_Clist glyphs;
+};
+
+struct _CS_Glyph_Out
+{
+ RGBA_Font_Glyph_Out base;
+ Eina_Clist map_entry;
+ Eina_Clist used_list;
+ unsigned int idx;
+ unsigned int rid;
+ Glyph_Map *map;
+ unsigned int offset;
+ unsigned int size;
+ Eina_Bool used;
+};
+
+static void
+_font_entry_free(Font_Entry *fe)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (fe->fash[i])
+ fash_gl_free(fe->fash[i]);
+
+ eina_stringshare_del(fe->source);
+ eina_stringshare_del(fe->name);
+ eina_hash_free(fe->glyphs_maps);
+ free(fe);
+}
+
+static void
+_glyphs_map_free(Glyph_Map *m)
+{
+ eina_file_map_free(m->map, m->data);
+ eina_file_close(m->map);
+ eina_stringshare_del(m->name);
+ free(m);
+}
+
+static void
+_glyph_out_free(void *gl)
+{
+ CS_Glyph_Out *glout = gl;
+
+ if (glout->map)
+ {
+ eina_clist_remove(&glout->map_entry);
+ if (eina_clist_empty(&glout->map->glyphs))
+ {
+ eina_hash_del(glout->map->fe->glyphs_maps, &glout->map->name,
+ NULL);
+ _glyphs_map_free(glout->map);
+ }
+ }
+
+ free(glout);
+}
+
+static void
+_font_loaded_cb(void *data, const void *msg)
+{
+ const Msg_Base *m = msg;
+ Font_Entry *fe = data;
+
+ fe->rid = 0;
+
+ if (m->type == CSERVE2_ERROR)
+ fe->failed = EINA_TRUE;
+}
+
+static unsigned int
+_font_load_server_send(Font_Entry *fe, Message_Type type)
+{
+ Msg_Font_Load *msg;
+ int source_len, path_len, size;
+ char *buf;
+ unsigned int ret = 0;
+ void (*cb)(void *data, const void *msg) = NULL;
+
+ if (!cserve2_init)
+ return 0;
+
+ source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
+ path_len = eina_stringshare_strlen(fe->name) + 1;
+
+ size = sizeof(*msg) + path_len + source_len;
+ msg = calloc(1, size);
+
+ msg->base.rid = _next_rid();
+ msg->base.type = type;
+
+ msg->sourcelen = source_len;
+ msg->pathlen = path_len;
+ msg->rend_flags = fe->wanted_rend;
+ msg->size = fe->size;
+ msg->dpi = fe->dpi;
+
+ buf = ((char *)msg) + sizeof(*msg);
+ memcpy(buf, fe->source, source_len);
+ buf += source_len;
+ memcpy(buf, fe->name, path_len);
+
+ if (type == CSERVE2_FONT_LOAD)
+ cb = _font_loaded_cb;
+
+ if (_server_send(msg, size, cb, fe))
+ ret = msg->base.rid;
+
+ free(msg);
+
+ return ret;
+}
+
+Font_Entry *
+evas_cserve2_font_load(const char *source, const char *name, int size, int dpi, Font_Rend_Flags wanted_rend)
+{
+ Font_Entry *fe;
+
+ fe = calloc(1, sizeof(Font_Entry));
+ if (!fe) return NULL;
+
+ fe->source = source ? eina_stringshare_add(source) : NULL;
+ fe->name = eina_stringshare_add(name);
+ fe->size = size;
+ fe->dpi = dpi;
+ fe->wanted_rend = wanted_rend;
+
+ if (!(fe->rid = _font_load_server_send(fe, CSERVE2_FONT_LOAD)))
+ {
+ eina_stringshare_del(fe->source);
+ eina_stringshare_del(fe->name);
+ free(fe);
+ return NULL;
+ }
+
+ fe->glyphs_maps = eina_hash_stringshared_new(NULL);
+ eina_clist_init(&fe->glyphs_queue);
+ eina_clist_init(&fe->glyphs_used);
+
+ return fe;
+}
+
+void
+evas_cserve2_font_free(Font_Entry *fe)
+{
+ if (!fe) return;
+
+ if (fe->failed)
+ return;
+
+ _font_load_server_send(fe, CSERVE2_FONT_UNLOAD);
+
+ _font_entry_free(fe);
+}
+
+typedef struct
+{
+ Font_Entry *fe;
+ Font_Hint_Flags hints;
+ unsigned int rid;
+} Glyph_Request_Data;
+
+static void
+_glyph_request_cb(void *data, const void *msg)
+{
+ const Msg_Font_Glyphs_Loaded *resp = msg;
+ Glyph_Request_Data *grd = data;
+ Font_Entry *fe = grd->fe;
+ unsigned int ncaches = 0;
+ const char *buf;
+
+ if (resp->base.type == CSERVE2_ERROR)
+ {
+ free(grd);
+ return;
+ }
+
+ buf = (const char *)resp + sizeof(*resp);
+ while (ncaches < resp->ncaches)
+ {
+ int i = 0, nglyphs;
+ int namelen;
+ const char *name;
+ Glyph_Map *map;
+
+ memcpy(&namelen, buf, sizeof(int));
+ buf += sizeof(int);
+
+ name = eina_stringshare_add_length(buf, namelen);
+ buf += namelen;
+
+ memcpy(&nglyphs, buf, sizeof(int));
+ buf += sizeof(int);
+
+ map = eina_hash_find(fe->glyphs_maps, name);
+ if (!map)
+ {
+ map = calloc(1, sizeof(*map));
+ map->fe = fe;
+ map->name = name;
+ map->map = eina_file_open(name, EINA_TRUE);
+ map->data = eina_file_map_all(map->map, EINA_FILE_WILLNEED);
+ eina_clist_init(&map->glyphs);
+ eina_hash_direct_add(fe->glyphs_maps, &map->name, map);
+ }
+ else
+ eina_stringshare_del(name);
+
+ while (i < nglyphs)
+ {
+ unsigned int idx, offset, glsize;
+ int rows, width, pitch, num_grays, pixel_mode;
+ CS_Glyph_Out *gl;
+
+ memcpy(&idx, buf, sizeof(int));
+ buf += sizeof(int);
+ memcpy(&offset, buf, sizeof(int));
+ buf += sizeof(int);
+ memcpy(&glsize, buf, sizeof(int));
+ buf += sizeof(int);
+ memcpy(&rows, buf, sizeof(int));
+ buf += sizeof(int);
+ memcpy(&width, buf, sizeof(int));
+ buf += sizeof(int);
+ memcpy(&pitch, buf, sizeof(int));
+ buf += sizeof(int);
+ memcpy(&num_grays, buf, sizeof(int));
+ buf += sizeof(int);
+ memcpy(&pixel_mode, buf, sizeof(int));
+ buf += sizeof(int);
+
+ gl = fash_gl_find(fe->fash[grd->hints], idx);
+ gl->map = map;
+ gl->offset = offset;
+ gl->size = glsize;
+ gl->base.bitmap.rows = rows;
+ gl->base.bitmap.width = width;
+ gl->base.bitmap.pitch = pitch;
+ gl->base.bitmap.buffer = map->data + gl->offset;
+ gl->base.bitmap.num_grays = num_grays;
+ gl->base.bitmap.pixel_mode = pixel_mode;
+
+ gl->rid = 0;
+
+ eina_clist_add_head(&map->glyphs, &gl->map_entry);
+
+ i++;
+ }
+
+ ncaches++;
+ }
+
+ free(grd);
+}
+
+static unsigned int
+_glyph_request_server_send(Font_Entry *fe, Font_Hint_Flags hints, Eina_Bool used)
+{
+ Msg_Font_Glyphs_Request *msg;
+ Glyph_Request_Data *grd = NULL;
+ int source_len, name_len, size, nglyphs;
+ char *buf;
+ unsigned int *glyphs;
+ unsigned int ret = 0;
+ Op_Callback cb;
+ Eina_Clist *queue, *itr, *itr_next;
+
+
+ source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
+ name_len = eina_stringshare_strlen(fe->name) + 1;
+
+ if (!used)
+ {
+ nglyphs = fe->glyphs_queue_count;
+ queue = &fe->glyphs_queue;
+ }
+ else
+ {
+ nglyphs = fe->glyphs_used_count;
+ queue = &fe->glyphs_used;
+ }
+
+ size = sizeof(*msg) + source_len + name_len + (nglyphs * sizeof(int));
+ msg = calloc(1, size);
+
+ msg->base.rid = _next_rid();
+ if (!used)
+ msg->base.type = CSERVE2_FONT_GLYPHS_LOAD;
+ else
+ msg->base.type = CSERVE2_FONT_GLYPHS_USED;
+
+ msg->sourcelen = source_len;
+ msg->pathlen = name_len;
+ msg->rend_flags = fe->wanted_rend;
+ msg->size = fe->size;
+ msg->dpi = fe->dpi;
+ msg->hint = hints;
+ msg->nglyphs = nglyphs;
+
+ buf = ((char *)msg) + sizeof(*msg);
+ memcpy(buf, fe->source, source_len);
+ buf += source_len;
+ memcpy(buf, fe->name, name_len);
+ buf += name_len;
+ glyphs = (unsigned int *)buf;
+ nglyphs = 0;
+ EINA_CLIST_FOR_EACH_SAFE(itr, itr_next, queue)
+ {
+ CS_Glyph_Out *gl;
+
+ if (!used)
+ {
+ gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, map_entry);
+ gl->rid = msg->base.rid;
+ eina_clist_remove(&gl->map_entry);
+ }
+ else
+ {
+ gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, used_list);
+ gl->used = EINA_FALSE;
+ eina_clist_remove(&gl->used_list);
+ }
+ glyphs[nglyphs++] = gl->idx;
+ }
+ if (!used)
+ fe->glyphs_queue_count = 0;
+ else
+ fe->glyphs_used_count = 0;
+
+ if (!used)
+ {
+ cb = _glyph_request_cb;
+ grd = malloc(sizeof(*grd));
+ grd->fe = fe;
+ grd->rid = msg->base.rid;
+ grd->hints = hints;
+ }
+ else
+ cb = NULL;
+
+ if (_server_send(msg, size, cb, grd))
+ ret = msg->base.rid;
+ else
+ free(grd);
+
+ free(msg);
+
+ return ret;
+}
+
+Eina_Bool
+evas_cserve2_font_glyph_request(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
+{
+ Fash_Glyph2 *fash;
+ CS_Glyph_Out *glyph;
+
+ if (fe->rid)
+ _server_dispatch_until(fe->rid);
+
+ if (fe->failed)
+ return EINA_FALSE;
+
+ fash = fe->fash[hints];
+ if (!fash)
+ {
+ fash = fash_gl_new(_glyph_out_free);
+ fe->fash[hints] = fash;
+ }
+
+ glyph = fash_gl_find(fash, idx);
+ if (!glyph)
+ {
+ glyph = calloc(1, sizeof(*glyph));
+
+ glyph->idx = idx;
+
+ fash_gl_add(fash, idx, glyph);
+
+ eina_clist_add_head(&fe->glyphs_queue, &glyph->map_entry);
+ fe->glyphs_queue_count++;
+ }
+ else if (!glyph->used)
+ {
+ eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
+ fe->glyphs_used_count++;
+ glyph->used = EINA_TRUE;
+ }
+
+ /* crude way to manage a queue, but it will work for now */
+ if (fe->glyphs_queue_count == 50)
+ _glyph_request_server_send(fe, hints, EINA_FALSE);
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+evas_cserve2_font_glyph_used(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
+{
+ Fash_Glyph2 *fash;
+ CS_Glyph_Out *glyph;
+
+ if (fe->rid)
+ _server_dispatch_until(fe->rid);
+
+ if (fe->failed)
+ return EINA_FALSE;
+
+ fash = fe->fash[hints];
+ if (!fash)
+ return EINA_FALSE;
+
+ glyph = fash_gl_find(fash, idx);
+ /* If we found the glyph on client cache, we should also have at least
+ * its request done.
+ */
+ if (!glyph)
+ return EINA_FALSE;
+
+ if (!glyph->map)
+ return EINA_TRUE;
+
+ if (glyph->used)
+ return EINA_TRUE;
+
+ eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
+ fe->glyphs_used_count++;
+ glyph->used = EINA_TRUE;
+
+ return EINA_TRUE;
+}
+
+RGBA_Font_Glyph_Out *
+evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
+{
+ Fash_Glyph2 *fash;
+ CS_Glyph_Out *out;
+
+ if (fe->failed)
+ return NULL;
+
+ /* quick hack, flush pending queue when we are asked for a bitmap */
+ if (fe->glyphs_queue_count)
+ _glyph_request_server_send(fe, hints, EINA_FALSE);
+
+ if (fe->glyphs_used_count)
+ _glyph_request_server_send(fe, hints, EINA_TRUE);
+
+ fash = fe->fash[hints];
+ if (!fash)
+ {
+ // this should not happen really, so let the user know he fucked up
+ system("format c:");
+ return NULL;
+ }
+
+ out = fash_gl_find(fash, idx);
+ if (!out)
+ {
+ // again, if we are asking for a bitmap we were supposed to already
+ // have requested the glyph, it must be there
+ return NULL;
+ }
+ if (out->rid)
+ _server_dispatch_until(out->rid);
+
+ // promote shm and font entry in lru or something
+
+ return &(out->base);
+}
+
#endif
};
typedef struct _Data_Entry Data_Entry;
+typedef struct _Font_Entry Font_Entry;
int evas_cserve2_init(void);
int evas_cserve2_shutdown(void);
void evas_cserve2_dispatch(void);
void *evas_cserve2_image_data_get(Image_Entry *ie);
+
+Font_Entry *evas_cserve2_font_load(const char *source, const char *name, int size, int dpi, Font_Rend_Flags wanted_rend);
+void evas_cserve2_font_free(Font_Entry *fe);
+Eina_Bool evas_cserve2_font_glyph_request(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints);
+Eina_Bool evas_cserve2_font_glyph_used(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints);
+RGBA_Font_Glyph_Out *evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints);
#endif
--- /dev/null
+/* THIS FILE TO BE SHARED WITH THE BIN PART. KEEP IT CLEAN. THERE BE DRAGONS */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <Eina.h>
+
+#include "evas_cs2_utils.h"
+
+/* fash */
+typedef struct _Fash_Glyph_Map Fash_Glyph_Map;
+typedef struct _Fash_Glyph_Map2 Fash_Glyph_Map2;
+
+struct _Fash_Glyph_Map
+{
+ void *item[256];
+};
+
+struct _Fash_Glyph_Map2
+{
+ Fash_Glyph_Map *bucket[256];
+};
+
+struct _Fash_Glyph2
+{
+ Fash_Glyph_Map2 *bucket[256];
+ void (*free_cb)(void *glyph);
+};
+
+static void
+_fash_item_free(Fash_Glyph2 *fash, Fash_Glyph_Map *map)
+{
+ int i;
+
+ if (fash->free_cb)
+ for (i = 0; i < 256; i++)
+ if (map->item[i])
+ fash->free_cb(map->item[i]);
+ free(map);
+}
+
+static void
+_fash_gl2_free(Fash_Glyph2 *fash, Fash_Glyph_Map2 *fash2)
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ if (fash2->bucket[i]) _fash_item_free(fash, fash2->bucket[i]);
+ free(fash2);
+}
+
+void
+fash_gl_free(Fash_Glyph2 *fash)
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ if (fash->bucket[i]) _fash_gl2_free(fash, fash->bucket[i]);
+ free(fash);
+}
+
+Fash_Glyph2 *
+fash_gl_new(void (*free_cb)(void *glyph))
+{
+ Fash_Glyph2 *fash = calloc(1, sizeof(Fash_Glyph2));
+ fash->free_cb = free_cb;
+ return fash;
+}
+
+void *
+fash_gl_find(Fash_Glyph2 *fash, int item)
+{
+ int grp, maj, min;
+
+ // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
+ grp = (item >> 16) & 0xff;
+ maj = (item >> 8) & 0xff;
+ min = item & 0xff;
+ if (!fash->bucket[grp]) return NULL;
+ if (!fash->bucket[grp]->bucket[maj]) return NULL;
+ return fash->bucket[grp]->bucket[maj]->item[min];
+}
+
+void
+fash_gl_add(Fash_Glyph2 *fash, int item, void *glyph)
+{
+ int grp, maj, min;
+
+ // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
+ grp = (item >> 16) & 0xff;
+ maj = (item >> 8) & 0xff;
+ min = item & 0xff;
+ if (!fash->bucket[grp])
+ fash->bucket[grp] = calloc(1, sizeof(Fash_Glyph_Map2));
+ EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]);
+ if (!fash->bucket[grp]->bucket[maj])
+ fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Glyph_Map));
+ EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
+ fash->bucket[grp]->bucket[maj]->item[min] = glyph;
+}
+
+void
+fash_gl_del(Fash_Glyph2 *fash, int item)
+{
+ int grp, maj, min;
+ void *data;
+
+ // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
+ grp = (item >> 16) & 0xff;
+ maj = (item >> 8) & 0xff;
+ min = item & 0xff;
+ if (!fash->bucket[grp]) return;
+ if (!fash->bucket[grp]->bucket[maj]) return;
+ if (!fash->bucket[grp]->bucket[maj]->item[min]) return;
+
+ data = fash->bucket[grp]->bucket[maj]->item[min];
+ fash->free_cb(data);
+ fash->bucket[grp]->bucket[maj]->item[min] = NULL;
+}
--- /dev/null
+/* THIS FILE TO BE SHARED WITH THE BIN PART. KEEP IT CLEAN. THERE BE DRAGONS */
+#ifndef _EVAS_CSERVE2_UTILS_H_
+#define _EVAS_CSERVE2_UTILS_H_
+
+typedef struct _Fash_Glyph2 Fash_Glyph2;
+
+Fash_Glyph2 *fash_gl_new(void (*free_cb)(void *glyph));
+void fash_gl_free(Fash_Glyph2 *fash);
+void *fash_gl_find(Fash_Glyph2 *fash, int item);
+void fash_gl_add(Fash_Glyph2 *fash, int item, void *glyph);
+void fash_gl_del(Fash_Glyph2 *fash, int item);
+
+#endif /* EVAS_CSERVE2_UTILS_H_ */
EAPI RGBA_Font_Int *evas_common_font_int_load (const char *name, int size, Font_Rend_Flags wanted_rend);
EAPI RGBA_Font_Int *evas_common_font_int_load_init (RGBA_Font_Int *fn);
EAPI RGBA_Font_Int *evas_common_font_int_load_complete (RGBA_Font_Int *fi);
-EAPI RGBA_Font *evas_common_font_memory_load (const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend);
+EAPI RGBA_Font *evas_common_font_memory_load (const char *source, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend);
EAPI RGBA_Font *evas_common_font_load (const char *name, int size, Font_Rend_Flags wanted_rend);
EAPI RGBA_Font *evas_common_font_add (RGBA_Font *fn, const char *name, int size, Font_Rend_Flags wanted_rend);
-EAPI RGBA_Font *evas_common_font_memory_add (RGBA_Font *fn, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend);
+EAPI RGBA_Font *evas_common_font_memory_add (RGBA_Font *fn, const char *source, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend);
EAPI void evas_common_font_free (RGBA_Font *fn);
+EAPI void evas_common_font_int_unref (RGBA_Font_Int *fi);
EAPI void evas_common_font_hinting_set (RGBA_Font *fn, Font_Hint_Flags hinting);
EAPI Eina_Bool evas_common_hinting_available (Font_Hint_Flags hinting);
-EAPI RGBA_Font *evas_common_font_memory_hinting_load (const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend);
+EAPI RGBA_Font *evas_common_font_memory_hinting_load (const char *source, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend);
EAPI RGBA_Font *evas_common_font_hinting_load (const char *name, int size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend);
EAPI RGBA_Font *evas_common_font_hinting_add (RGBA_Font *fn, const char *name, int size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend);
-EAPI RGBA_Font *evas_common_font_memory_hinting_add (RGBA_Font *fn, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend);
+EAPI RGBA_Font *evas_common_font_memory_hinting_add (RGBA_Font *fn, const char *source, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend);
EAPI void evas_common_font_int_modify_cache_by (RGBA_Font_Int *fi, int dir);
EAPI int evas_common_font_cache_get (void);
EAPI void evas_common_font_cache_set (int size);
#define EVAS_FONT_WALK_IS_VISIBLE (_glyph_itr->index != 0)
#define EVAS_FONT_WALK_X_BEAR (_glyph_itr->x_bear)
-#define EVAS_FONT_WALK_Y_BEAR (fg->glyph_out->top)
+#define EVAS_FONT_WALK_Y_BEAR (_glyph_itr->y_bear)
#define EVAS_FONT_WALK_X_ADV ((_glyph_itr > text_props->info->glyph) ? \
_glyph_itr->pen_after - (_glyph_itr - 1)->pen_after : \
_glyph_itr->pen_after)
#include "evas_font_ot.h"
-struct prword
-{
- EINA_INLIST;
- struct cinfo *cinfo;
- Evas_Text_Props text_props;
- DATA8 *im;
- int roww;
- int width;
- int height;
- int baseline;
-};
-
-struct cinfo
-{
- FT_UInt index;
- struct
- {
- int x, y;
- } pos;
- int posx;
- RGBA_Font_Glyph *fg;
- struct
- {
- int w,h;
- int rows;
- unsigned char *data;
- } bm;
-};
-
typedef struct _Evas_Glyph Evas_Glyph;
struct _Evas_Glyph
{
length = eina_binbuf_length_get(text_props->bin) / sizeof (Evas_Glyph);
for (it = 0; it < length; ++it)
{
- FT_UInt idx;
RGBA_Font_Glyph *fg;
int chr_x, chr_y;
fg = glyphs[it].fg;
- idx = glyphs[it].idx;
+
+ glyphs[it].coord.w = fg->glyph_out->bitmap.width;
+ glyphs[it].coord.h = fg->glyph_out->bitmap.rows;
+ glyphs[it].j = fg->glyph_out->bitmap.pitch;
+ glyphs[it].data = fg->glyph_out->bitmap.buffer;
if (dc->font_ext.func.gl_new)
{
w = glyphs[it].coord.w;
if (j < w) j = w;
h = glyphs[it].coord.h;
- /*
- if ((fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays)
- && (fg->glyph_out->bitmap.num_grays == 256)
- )
- */
#ifdef HAVE_PIXMAN
# ifdef PIXMAN_FONT
evas_common_font_draw_prepare(Evas_Text_Props *text_props)
{
RGBA_Font_Int *fi;
+ RGBA_Font_Glyph *fg;
EVAS_FONT_WALK_TEXT_INIT();
fi = text_props->font_instance;
EVAS_FONT_WALK_TEXT_START()
{
Evas_Glyph glyph;
- RGBA_Font_Glyph *fg;
FT_UInt idx;
if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
glyph.fg = fg;
glyph.coord.x = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR;
glyph.coord.y = EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR;
- glyph.coord.w = fg->glyph_out->bitmap.width;
- glyph.coord.h = fg->glyph_out->bitmap.rows;
- glyph.j = fg->glyph_out->bitmap.pitch;
glyph.idx = idx;
- glyph.data = fg->glyph_out->bitmap.buffer;
eina_binbuf_append_length(text_props->bin, (void*) &glyph, sizeof (Evas_Glyph));
}
EVAS_FONT_WALK_TEXT_END();
+ /* check if there's a request queue in fi, if so ask cserve2 to render
+ * those glyphs
+ */
+
text_props->generation = fi->generation;
}
#include "evas_font_private.h" /* for Frame-Queuing support */
#include "evas_font_ot.h"
+#ifdef EVAS_CSERVE2
+# include "../../cserve2/evas_cs2_private.h"
+#endif
+
#ifdef USE_HARFBUZZ
# include <hb.h>
# include <hb-ft.h>
hb_font_destroy(fi->ft.hb_font);
#endif
evas_common_font_source_free(fi->src);
- if (fi->references == 0) fonts_lru = eina_list_remove(fonts_lru, fi);
+ if (fi->references <= 0) fonts_lru = eina_list_remove(fonts_lru, fi);
if (fi->fash) fi->fash->freeme(fi->fash);
if (fi->inuse)
{
fonts_use_usage -= fi->usage;
fi->usage = 0;
}
+#ifdef EVAS_CSERVE2
+ evas_cserve2_font_free(fi->cs2_handler);
+#endif
free(fi);
}
}
EAPI RGBA_Font_Int *
-evas_common_font_int_memory_load(const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
+evas_common_font_int_memory_load(const char *source, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
{
RGBA_Font_Int *fi;
+ char *fake_name;
- fi = evas_common_font_int_find(name, size, wanted_rend);
- if (fi) return fi;
+ fake_name = evas_file_path_join(source, name);
+ fi = evas_common_font_int_find(fake_name, size, wanted_rend);
+ if (fi)
+ {
+ free(fake_name);
+ return fi;
+ }
fi = calloc(1, sizeof(RGBA_Font_Int));
- if (!fi) return NULL;
- fi->src = evas_common_font_source_find(name);
+ if (!fi)
+ {
+ free(fake_name);
+ return NULL;
+ }
+ fi->src = evas_common_font_source_find(fake_name);
if (!fi->src)
- fi->src = evas_common_font_source_memory_load(name, data, data_size);
+ fi->src = evas_common_font_source_memory_load(fake_name, data, data_size);
if (!fi->src)
{
free(fi);
+ free(fake_name);
return NULL;
}
fi->size = size;
_evas_common_font_int_cache_init(fi);
fi = evas_common_font_int_load_init(fi);
evas_common_font_int_load_complete(fi);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ fi->cs2_handler = evas_cserve2_font_load(source, name, size, font_dpi,
+ wanted_rend);
+#endif
+ free(fake_name);
return fi;
}
fi->wanted_rend = wanted_rend;
_evas_common_font_int_cache_init(fi);
fi = evas_common_font_int_load_init(fi);
+#ifdef EVAS_CSERVE2
+ if (evas_cserve2_use_get())
+ fi->cs2_handler = evas_cserve2_font_load(NULL, name, size, font_dpi,
+ wanted_rend);
+#endif
// evas_common_font_int_load_complete(fi);
return fi;
}
}
EAPI RGBA_Font *
-evas_common_font_memory_load(const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
+evas_common_font_memory_load(const char *source, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
{
RGBA_Font *fn;
RGBA_Font_Int *fi;
- fi = evas_common_font_int_memory_load(name, size, data, data_size,
+ fi = evas_common_font_int_memory_load(source, name, size, data, data_size,
wanted_rend);
if (!fi) return NULL;
fn = calloc(1, sizeof(RGBA_Font));
if (!fn)
{
- fi->references--;
- if (fi->references == 0)
- {
- fonts_lru = eina_list_prepend(fonts_lru, fi);
- evas_common_font_int_modify_cache_by(fi, 1);
- evas_common_font_flush();
- }
+ evas_common_font_int_unref(fi);
return NULL;
}
fn->fonts = eina_list_append(fn->fonts, fi);
{
if (evas_common_font_source_load_complete(fi->src))
{
- fi->references--;
- if (fi->references == 0)
- {
- fonts_lru = eina_list_prepend(fonts_lru, fi);
- evas_common_font_int_modify_cache_by(fi, 1);
- evas_common_font_flush();
- }
+ evas_common_font_int_unref(fi);
return NULL;
}
}
fn = calloc(1, sizeof(RGBA_Font));
if (!fn)
{
- fi->references--;
- if (fi->references == 0)
- {
- fonts_lru = eina_list_prepend(fonts_lru, fi);
- evas_common_font_int_modify_cache_by(fi, 1);
- evas_common_font_flush();
- }
+ evas_common_font_int_unref(fi);
return NULL;
}
}
EAPI RGBA_Font *
-evas_common_font_memory_add(RGBA_Font *fn, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
+evas_common_font_memory_add(RGBA_Font *fn, const char *source, const char *name, int size, const void *data, int data_size, Font_Rend_Flags wanted_rend)
{
RGBA_Font_Int *fi;
if (!fn)
return NULL;
- fi = evas_common_font_int_memory_load(name, size, data, data_size, wanted_rend);
+ fi = evas_common_font_int_memory_load(source, name, size, data, data_size, wanted_rend);
if (fi)
{
fn->fonts = eina_list_append(fn->fonts, fi);
}
EAPI void
+evas_common_font_int_unref(RGBA_Font_Int *fi)
+{
+ fi->references--;
+ if (fi->references == 0)
+ {
+ fonts_lru = eina_list_append(fonts_lru, fi);
+ evas_common_font_int_modify_cache_by(fi, 1);
+ evas_common_font_flush();
+ }
+}
+
+EAPI void
evas_common_font_free(RGBA_Font *fn)
{
Eina_List *l;
fn->references--;
if (fn->references > 0) return;
EINA_LIST_FOREACH(fn->fonts, l, fi)
- {
- fi->references--;
- if (fi->references == 0)
- {
- fonts_lru = eina_list_append(fonts_lru, fi);
- evas_common_font_int_modify_cache_by(fi, 1);
- }
- }
+ evas_common_font_int_unref(fi);
evas_common_font_flush();
eina_list_free(fn->fonts);
if (fn->fash) fn->fash->freeme(fn->fash);
}
EAPI RGBA_Font *
-evas_common_font_memory_hinting_load(const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
+evas_common_font_memory_hinting_load(const char *source, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
{
RGBA_Font *fn;
- fn = evas_common_font_memory_load(name, size, data, data_size, wanted_rend);
+ fn = evas_common_font_memory_load(source, name, size, data, data_size, wanted_rend);
if (fn) evas_common_font_hinting_set(fn, hinting);
return fn;
}
}
EAPI RGBA_Font *
-evas_common_font_memory_hinting_add(RGBA_Font *fn, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
+evas_common_font_memory_hinting_add(RGBA_Font *fn, const char *source, const char *name, int size, const void *data, int data_size, Font_Hint_Flags hinting, Font_Rend_Flags wanted_rend)
{
- fn = evas_common_font_memory_add(fn, name, size, data, data_size,
+ fn = evas_common_font_memory_add(fn, source, name, size, data, data_size,
wanted_rend);
if (fn) evas_common_font_hinting_set(fn, hinting);
return fn;
return;
}
evas_common_font_int_modify_cache_by(fi, -1);
- if (fi->fash)
- {
- for (k = 0; k <= 0xff; k++) // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
- {
- Fash_Glyph_Map2 *fmap2 = fi->fash->bucket[k];
- if (fmap2)
- {
- for (j = 0; j <= 0xff; j++) // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
- {
- Fash_Glyph_Map *fmap = fmap2->bucket[j];
- if (fmap)
+ if (fi->references <= 1)
+ {
+ if (fi->fash)
+ {
+ for (k = 0; k <= 0xff; k++) // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
+ {
+ Fash_Glyph_Map2 *fmap2 = fi->fash->bucket[k];
+ if (fmap2)
{
- for (i = 0; i <= 0xff; i++)
- {
- RGBA_Font_Glyph *fg = fmap->item[i];
- if ((fg) && (fg != (void *)(-1)))
- {
- FT_Done_Glyph(fg->glyph);
- /* extension calls */
- if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
- free(fg);
- fmap->item[i] = NULL;
- }
- }
+ for (j = 0; j <= 0xff; j++) // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
+ {
+ Fash_Glyph_Map *fmap = fmap2->bucket[j];
+ if (fmap)
+ {
+ for (i = 0; i <= 0xff; i++)
+ {
+ RGBA_Font_Glyph *fg = fmap->item[i];
+ if ((fg) && (fg != (void *)(-1)))
+ {
+ FT_Done_Glyph(fg->glyph);
+ /* extension calls */
+ if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
+ if (fg->glyph_out_free) fg->glyph_out_free(fg->glyph_out);
+ free(fg);
+ fmap->item[i] = NULL;
+ }
+ }
+ }
+ }
}
- }
- }
- }
- fi->fash->freeme(fi->fash);
- fi->fash = NULL;
+ }
+ fi->fash->freeme(fi->fash);
+ fi->fash = NULL;
+ }
}
if (fi->inuse) fonts_use_usage -= fi->usage;
fi->usage = 0;
#include "evas_font_private.h"
+#ifdef EVAS_CSERVE2
+# include "../../cserve2/evas_cs2_private.h"
+#endif
+
#include <assert.h>
#include FT_OUTLINE_H
fi->src->current_size = fi->size;
}
val = (int)fi->src->ft.face->size->metrics.height;
- if (fi->src->ft.face->units_per_EM == 0)
+ if ((fi->src->ft.face->bbox.yMax == 0) &&
+ (fi->src->ft.face->bbox.yMin == 0) &&
+ (fi->src->ft.face->units_per_EM == 0))
+ return val >> 6;
+ else if (fi->src->ft.face->units_per_EM == 0)
return val;
return val >> 6;
// dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
{
fg = _fash_gl_find(fi->fash, idx);
if (fg == (void *)(-1)) return NULL;
- else if (fg) return fg;
+ else if (fg)
+ {
+#ifdef EVAS_CSERVE2
+ if (fi->cs2_handler)
+ evas_cserve2_font_glyph_used(fi->cs2_handler, idx,
+ fi->hinting);
+#endif
+ return fg;
+ }
}
-
// fg = eina_hash_find(fi->glyphs, &hindex);
// if (fg) return fg;
{
FT_BBox outbox;
- FT_Glyph_Get_CBox(fg->glyph, FT_GLYPH_BBOX_UNSCALED,
+ FT_Glyph_Get_CBox(fg->glyph,
+ ((fi->hinting == 0) ? FT_GLYPH_BBOX_UNSCALED :
+ FT_GLYPH_BBOX_GRIDFIT),
&outbox);
fg->width = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMax - outbox.xMin);
fg->x_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMin);
+ fg->y_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.yMax);
}
fg->index = idx;
if (!fi->fash) fi->fash = _fash_gl_new();
if (fi->fash) _fash_gl_add(fi->fash, idx, fg);
+#ifdef EVAS_CSERVE2
+ if (fi->cs2_handler)
+ evas_cserve2_font_glyph_request(fi->cs2_handler, idx, fi->hinting);
+#endif
+
// eina_hash_direct_add(fi->glyphs, &fg->index, fg);
return fg;
}
int size;
FT_Error error;
RGBA_Font_Int *fi = fg->fi;
+ FT_BitmapGlyph fbg;
+
+#ifdef EVAS_CSERVE2
+ if (fi->cs2_handler)
+ {
+ fg->glyph_out = evas_cserve2_font_glyph_bitmap_get(fi->cs2_handler,
+ fg->index,
+ fg->fi->hinting);
+ if (fg->glyph_out)
+ return EINA_TRUE;
+ }
+#endif
+
+ /* no cserve2 case */
FTLOCK();
error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1);
if (error)
}
FTUNLOCK();
- fg->glyph_out = (FT_BitmapGlyph)fg->glyph;
+ fbg = (FT_BitmapGlyph)fg->glyph;
+
+ fg->glyph_out = malloc(sizeof(RGBA_Font_Glyph_Out));
+ fg->glyph_out->bitmap.rows = fbg->bitmap.rows;
+ fg->glyph_out->bitmap.width = fbg->bitmap.width;
+ fg->glyph_out->bitmap.pitch = fbg->bitmap.pitch;
+ fg->glyph_out->bitmap.buffer = fbg->bitmap.buffer;
+ fg->glyph_out->bitmap.num_grays = fbg->bitmap.num_grays;
+ fg->glyph_out->bitmap.pixel_mode = fbg->bitmap.pixel_mode;
+
+ fg->glyph_out_free = free;
/* This '+ 200' is just an estimation of how much memory freetype will use
* on it's size. This value is not really used anywhere in code - it's
* only for statistics. */
EAPI FT_UInt
evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
{
+ static const unsigned short mapfix[] =
+ {
+ 0x00b0, 0x7,
+ 0x00b1, 0x8,
+ 0x00b7, 0x1f,
+ 0x03c0, 0x1c,
+ 0x20a4, 0xa3,
+ 0x2260, 0x1d,
+ 0x2264, 0x1a,
+ 0x2265, 0x1b,
+ 0x23ba, 0x10,
+ 0x23bb, 0x11,
+ 0x23bc, 0x13,
+ 0x23bd, 0x14,
+ 0x2409, 0x3,
+ 0x240a, 0x6,
+ 0x240b, 0xa,
+ 0x240c, 0x4,
+ 0x240d, 0x5,
+ 0x2424, 0x9,
+ 0x2500, 0x12,
+ 0x2502, 0x19,
+ 0x250c, 0xd,
+ 0x2510, 0xc,
+ 0x2514, 0xe,
+ 0x2518, 0xb,
+ 0x251c, 0x15,
+ 0x2524, 0x16,
+ 0x252c, 0x18,
+ 0x2534, 0x17,
+ 0x253c, 0xf,
+ 0x2592, 0x2,
+ 0x25c6, 0x1,
+ };
Font_Char_Index result;
//FT_UInt ret;
#ifdef HAVE_PTHREAD
// pthread_mutex_unlock(&fi->ft_mutex);
#endif
+ // this is a workaround freetype bugs where for a bitmap old style font
+ // even if it has unicode information and mappings, they are not used
+ // to find terminal line/drawing chars, so do this by hand with a table
+ if ((result.index <= 0) && (fi->src->ft.face->num_fixed_sizes == 1) &&
+ (fi->src->ft.face->num_glyphs < 512))
+ {
+ int i, min = 0, max;
+
+ // binary search through sorted table of codepoints to new
+ // codepoints with a guess that bitmap font is playing the old
+ // game of putting line drawing chars in specific ranges
+ max = sizeof(mapfix) / (sizeof(mapfix[0]) * 2);
+ i = (min + max) / 2;
+ for (;;)
+ {
+ unsigned short v;
+
+ v = mapfix[i << 1];
+ if (gl == v)
+ {
+ gl = mapfix[(i << 1) + 1];
+ FTLOCK();
+ result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
+ FTUNLOCK();
+ break;
+ }
+ // failure to find at all
+ if ((max - min) <= 2) break;
+ // if glyph above out position...
+ if (gl > v)
+ {
+ min = i;
+ if ((max - min) == 2) i = max;
+ else i = (min + max) / 2;
+ }
+ // if glyph below out position
+ else if (gl < v)
+ {
+ max = i;
+ if ((max - min) == 2) i = min;
+ else i = (min + max) / 2;
+ }
+ }
+ }
return result.index;
}
Evas_Coord ret_adv = 0;
if (text_props->len > 0)
{
- RGBA_Font_Int *fi = text_props->font_instance;
+// RGBA_Font_Int *fi = text_props->font_instance;
const Evas_Font_Glyph_Info *glyph = text_props->info->glyph +
text_props->start;
const Evas_Font_Glyph_Info *last_glyph = glyph + text_props->len - 1;
return;
props->info->refcount++;
+ if (props->font_instance)
+ ((RGBA_Font_Int *)props->font_instance)->references++;
}
void
if (!props->info)
return;
+ if (props->font_instance)
+ {
+ evas_common_font_int_unref(props->font_instance);
+ props->font_instance = NULL;
+ }
+
if (--(props->info->refcount) == 0)
{
if (props->bin)
LKU(fi->ft_mutex);
gl_itr->x_bear = fg->x_bear;
+ gl_itr->y_bear = fg->y_bear;
gl_itr->width = fg->width;
/* text_props->info->glyph[char_index].advance =
* text_props->info->glyph[char_index].index =
gl_itr->index = idx;
gl_itr->x_bear = fg->x_bear;
+ gl_itr->y_bear = fg->y_bear;
adv = fg->glyph->advance.x >> 10;
gl_itr->width = fg->width;
}
text_props->info = calloc(1, sizeof(Evas_Text_Props_Info));
- text_props->font_instance = fi;
-
+ if (text_props->font_instance != fi)
+ {
+ if (text_props->font_instance)
+ evas_common_font_int_unref(text_props->font_instance);
+ text_props->font_instance = fi;
+ fi->references++;
+ }
+
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
{
{
unsigned int index; /* Should conform to FT */
Evas_Coord x_bear;
-#if 0
/* This one is rarely used, only in draw, in which we already get the glyph
* so it doesn't really save time. Leaving it here just so no one will
* add it thinking it was accidentally skipped */
Evas_Coord y_bear;
-#endif
Evas_Coord width;
Evas_Coord pen_after;
};
EVAS_EINA_STATIC_MODULE_DEFINE(engine, gl_sdl);
EVAS_EINA_STATIC_MODULE_DEFINE(engine, psl1ght);
EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16);
-EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16_ddraw);
EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16_sdl);
EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16_wince);
EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16_x11);
#ifdef EVAS_STATIC_BUILD_SOFTWARE_16
EVAS_EINA_STATIC_MODULE_USE(engine, software_16),
#endif
-#ifdef EVAS_STATIC_BUILD_SOFTWARE_16_DDRAW
- EVAS_EINA_STATIC_MODULE_USE(engine, software_16_ddraw),
-#endif
#ifdef EVAS_STATIC_BUILD_SOFTWARE_16_SDL
EVAS_EINA_STATIC_MODULE_USE(engine, software_16_sdl),
#endif
#ifdef EVAS_STATIC_BUILD_SOFTWARE_16_X11
EVAS_EINA_STATIC_MODULE_USE(engine, software_16_x11),
#endif
-#ifdef EVAS_STATIC_BUILD_SOFTWARE_16_DDRAW
- EVAS_EINA_STATIC_MODULE_USE(engine, software_ddraw),
-#endif
-#ifdef EVAS_STATIC_BUILD_SOFTWARE_16_GDI
- EVAS_EINA_STATIC_MODULE_USE(engine, software_gdi),
-#endif
#ifdef EVAS_STATIC_BUILD_SOFTWARE_8
EVAS_EINA_STATIC_MODULE_USE(engine, software_8),
#endif
#ifdef EVAS_STATIC_BUILD_SOFTWARE_8_X11
EVAS_EINA_STATIC_MODULE_USE(engine, software_8_x11),
#endif
+#ifdef EVAS_STATIC_BUILD_SOFTWARE_DDRAW
+ EVAS_EINA_STATIC_MODULE_USE(engine, software_ddraw),
+#endif
+#ifdef EVAS_STATIC_BUILD_SOFTWARE_GDI
+ EVAS_EINA_STATIC_MODULE_USE(engine, software_gdi),
+#endif
#ifdef EVAS_STATIC_BUILD_SOFTWARE_GENERIC
EVAS_EINA_STATIC_MODULE_USE(engine, software_generic),
#endif
typedef struct _RGBA_Font_Int RGBA_Font_Int;
typedef struct _RGBA_Font_Source RGBA_Font_Source;
typedef struct _RGBA_Font_Glyph RGBA_Font_Glyph;
+typedef struct _RGBA_Font_Glyph_Out RGBA_Font_Glyph_Out;
typedef struct _RGBA_Gfx_Compositor RGBA_Gfx_Compositor;
typedef struct _Cutout_Rect Cutout_Rect;
in order to comply with the wanted_rend. */
Eina_List *task;
+#ifdef EVAS_CSERVE2
+ void *cs2_handler;
+#endif
int generation;
} ft;
};
+/*
+ * laziness wins for now. The parts used from the freetpye struct are
+ * kept intact to avoid changing the code using it until we know exactly
+ * what needs to be changed
+ */
+struct _RGBA_Font_Glyph_Out
+{
+ struct {
+ int rows;
+ int width;
+ int pitch;
+ unsigned char *buffer;
+ short num_grays;
+ char pixel_mode;
+ } bitmap;
+};
+
struct _RGBA_Font_Glyph
{
FT_UInt index;
Evas_Coord width;
Evas_Coord x_bear;
+ Evas_Coord y_bear;
FT_Glyph glyph;
- FT_BitmapGlyph glyph_out;
+ RGBA_Font_Glyph_Out *glyph_out;
+ void (*glyph_out_free)(void *);
/* this is a problem - only 1 engine at a time can extend such a font... grrr */
void *ext_dat;
void (*ext_dat_free) (void *ext_dat);
int (*image_cache_get) (void *data);
Evas_Font_Set *(*font_load) (void *data, const char *name, int size, Font_Rend_Flags wanted_rend);
- Evas_Font_Set *(*font_memory_load) (void *data, char *name, int size, const void *fdata, int fdata_size, Font_Rend_Flags wanted_rend);
+ Evas_Font_Set *(*font_memory_load) (void *data, const char *source, const char *name, int size, const void *fdata, int fdata_size, Font_Rend_Flags wanted_rend);
Evas_Font_Set *(*font_add) (void *data, Evas_Font_Set *font, const char *name, int size, Font_Rend_Flags wanted_rend);
- Evas_Font_Set *(*font_memory_add) (void *data, Evas_Font_Set *font, char *name, int size, const void *fdata, int fdata_size, Font_Rend_Flags wanted_rend);
+ Evas_Font_Set *(*font_memory_add) (void *data, Evas_Font_Set *font, const char *source, const char *name, int size, const void *fdata, int fdata_size, Font_Rend_Flags wanted_rend);
void (*font_free) (void *data, Evas_Font_Set *font);
int (*font_ascent_get) (void *data, Evas_Font_Set *font);
int (*font_descent_get) (void *data, Evas_Font_Set *font);
if !EVAS_STATIC_BUILD_SOFTWARE_16
SUBDIRS += software_16
endif
-if !EVAS_STATIC_BUILD_SOFTWARE_16_DDRAW
-SUBDIRS += software_16_ddraw
-endif
if !EVAS_STATIC_BUILD_SOFTWARE_16_WINCE
SUBDIRS += software_16_wince
endif
#endif
XVisualInfo *vi_use;
const GLubyte *vendor, *renderer, *version;
+ int blacklist = 0;
if (!_evas_gl_x11_vi) return NULL;
fprintf(stderr, "renderer: %s\n", renderer);
fprintf(stderr, "version: %s\n", version);
}
+
+ if (strstr((const char *)vendor, "Mesa Project"))
+ {
+ if (strstr((const char *)renderer, "Software Rasterizer"))
+ blacklist = 1;
+ }
+ if (strstr((const char *)renderer, "softpipe"))
+ blacklist = 1;
+ if (blacklist)
+ {
+ ERR("OpenGL Driver blacklisted:");
+ ERR("Vendor: %s", (const char *)vendor);
+ ERR("Renderer: %s", (const char *)renderer);
+ ERR("Version: %s", (const char *)version);
+ eng_window_free(gw);
+ return NULL;
+ }
// GLX
#else
if (!context)
{
int i, j, num;
GLXFBConfig *fbc;
- int blacklist = 0;
if (gw->glxwin)
{
+++ /dev/null
-#ifndef __EVAS_ENGINE_SOFTWARE_16_DDRAW_H__
-#define __EVAS_ENGINE_SOFTWARE_16_DDRAW_H__
-
-
-#include <windows.h>
-#include <ddraw.h>
-
-typedef struct _Evas_Engine_Info_Software_16_DDraw Evas_Engine_Info_Software_16_DDraw;
-
-struct _Evas_Engine_Info_Software_16_DDraw
-{
- /* PRIVATE - don't mess with this baby or evas will poke its tongue out */
- /* at you and make nasty noises */
- Evas_Engine_Info magic;
-
- struct {
- HWND window;
- LPDIRECTDRAW object; /* DirectDraw object */
- LPDIRECTDRAWSURFACE surface_primary; /* DirectDraw primary surface */
- LPDIRECTDRAWSURFACE surface_back; /* DirectDraw back surface */
- LPDIRECTDRAWSURFACE surface_source; /* DirectDraw source surface */
- int depth;
-
- int rotation;
- } info;
-
- /* non-blocking or blocking mode */
- Evas_Engine_Render_Mode render_mode;
-};
-
-
-#endif /* __EVAS_ENGINE_SOFTWARE_16_DDRAW_H__ */
+++ /dev/null
-
-MAINTAINERCLEANFILES = Makefile.in
-
-AM_CPPFLAGS = \
--I. \
--I$(top_srcdir)/src/lib \
--I$(top_srcdir)/src/lib/include \
--I$(top_srcdir)/src/modules/engines \
--I$(top_srcdir)/src/modules/engines/software_16 \
-@EINA_CFLAGS@ \
-@FREETYPE_CFLAGS@ \
-@PIXMAN_CFLAGS@ \
-@FRIBIDI_CFLAGS@ \
-@evas_engine_software_16_ddraw_cflags@
-
-if BUILD_ENGINE_SOFTWARE_16_DDRAW
-
-SOFTWARE_16_DDRAW_SOURCES = \
-evas_engine.c \
-evas_ddraw_buffer.cpp \
-evas_ddraw_main.cpp
-
-SOFTWARE_16_DDRAW_LIBADD = @evas_engine_software_16_ddraw_libs@
-
-
-includes_HEADERS = Evas_Engine_Software_16_DDraw.h
-includesdir = $(includedir)/evas-@VMAJ@
-
-if !EVAS_STATIC_BUILD_SOFTWARE_16_DDRAW
-
-pkgdir = $(libdir)/evas/modules/engines/software_16_ddraw/$(MODULE_ARCH)
-pkg_LTLIBRARIES = module.la
-
-module_la_SOURCES = $(SOFTWARE_16_DDRAW_SOURCES)
-module_la_CXXFLAGS = -fno-rtti -fno-exceptions
-module_la_LIBADD = $(top_builddir)/src/lib/libevas.la @EINA_LIBS@ $(SOFTWARE_16_DDRAW_LIBADD)
-module_la_LDFLAGS = @lt_enable_auto_import@ -no-undefined -module -avoid-version
-module_la_LIBTOOLFLAGS = --tag=disable-static
-
-else
-
-noinst_LTLIBRARIES = libevas_engine_software_16_ddraw.la
-
-libevas_engine_software_16_ddraw_la_SOURCES = $(SOFTWARE_16_DDRAW_SOURCES)
-libevas_engine_software_16_ddraw_la_LIBADD = $(SOFTWARE_16_DDRAW_LIBADD)
-
-endif
-endif
-
-EXTRA_DIST = evas_engine.h
+++ /dev/null
-#include "evas_common.h"
-#include "evas_engine.h"
-
-
-DDraw_Output_Buffer *
-evas_software_ddraw_output_buffer_new(HWND window,
- LPDIRECTDRAW object,
- LPDIRECTDRAWSURFACE surface_primary,
- LPDIRECTDRAWSURFACE surface_back,
- LPDIRECTDRAWSURFACE surface_source,
- int width,
- int height)
-{
- DDSURFACEDESC surface_desc;
- DDraw_Output_Buffer *ddob;
-
- ddob = (DDraw_Output_Buffer *)calloc(1, sizeof(DDraw_Output_Buffer));
- if (!ddob) return NULL;
-
- ddob->dd.window = window;
- ddob->dd.object = object;
- ddob->dd.surface_primary = surface_primary;
- ddob->dd.surface_back = surface_back;
- ddob->dd.surface_source = surface_source;
- ddob->width = width;
- ddob->height = height;
- ddob->pitch = width * 2;
-
- ZeroMemory(&surface_desc, sizeof(surface_desc));
- surface_desc.dwSize = sizeof(surface_desc);
-
- if (FAILED(ddob->dd.surface_source->Lock(NULL,
- &surface_desc,
- DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
- NULL)))
- {
- free(ddob);
- return NULL;
- }
-
- ddob->data = (DATA16 *)surface_desc.lpSurface;
-
- if (FAILED(ddob->dd.surface_source->Unlock(NULL)))
- {
- free(ddob);
- return NULL;
- }
- if (ddob->im)
- evas_cache_image_drop(&ddob->im->cache_entry);
-
- ddob->im = (Soft16_Image *) evas_cache_image_data(evas_common_soft16_image_cache_get(), width, height, (DATA32 *) ddob->data, 0, EVAS_COLORSPACE_RGB565_A5P);
- if (ddob->im)
- ddob->im->stride = ddob->pitch;
-
- return ddob;
-}
-
-void
-evas_software_ddraw_output_buffer_free(DDraw_Output_Buffer *ddob, int sync)
-{
- free(ddob);
-}
-
-void
-evas_software_ddraw_output_buffer_paste(DDraw_Output_Buffer *ddob)
-{
- RECT dst_rect;
- RECT src_rect;
- POINT p;
-
- SetRect(&src_rect, 0, 0, ddob->width, ddob->height);
-
- if (FAILED(ddob->dd.surface_back->BltFast(0, 0,
- ddob->dd.surface_source,
- &src_rect,
- DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)))
- return;
-
- p.x = 0;
- p.y = 0;
- ClientToScreen(ddob->dd.window, &p);
- GetClientRect(ddob->dd.window, &dst_rect);
- OffsetRect(&dst_rect, p.x, p.y);
- ddob->dd.surface_primary->Blt(&dst_rect,
- ddob->dd.surface_back, &src_rect,
- DDBLT_WAIT, NULL);
-}
+++ /dev/null
-#include "evas_engine.h"
-
-
-void *
-evas_software_ddraw_lock(DDraw_Output_Buffer *ddob, int *ddraw_width, int *ddraw_height, int *ddraw_pitch, int *ddraw_depth)
-{
- DDSURFACEDESC surface_desc;
-
- ZeroMemory(&surface_desc, sizeof(surface_desc));
- surface_desc.dwSize = sizeof(surface_desc);
-
- if (FAILED(ddob->dd.surface_back->Lock(NULL,
- &surface_desc,
- DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY,
- NULL)))
- return NULL;
-
- *ddraw_width = surface_desc.dwWidth;
- *ddraw_height = surface_desc.dwHeight;
- *ddraw_pitch = surface_desc.lPitch;
- *ddraw_depth = surface_desc.ddpfPixelFormat.dwRGBBitCount >> 3;
-
- return surface_desc.lpSurface;
-}
-
-void
-evas_software_ddraw_unlock_and_flip(DDraw_Output_Buffer *ddob)
-{
- RECT dst_rect;
- RECT src_rect;
- POINT p;
-
- if (FAILED(ddob->dd.surface_back->Unlock(NULL)))
- return;
-
- /* we figure out where on the primary surface our window lives */
- p.x = 0;
- p.y = 0;
- ClientToScreen(ddob->dd.window, &p);
- GetClientRect(ddob->dd.window, &dst_rect);
- OffsetRect(&dst_rect, p.x, p.y);
- SetRect(&src_rect, 0, 0, ddob->width, ddob->height);
-
- /* nothing to do if the function fails, so we don't check the result */
- ddob->dd.surface_primary->BltFast(0, 0,
- ddob->dd.surface_back, &dst_rect,
- DDBLTFAST_WAIT || DDBLTFAST_NOCOLORKEY);
-}
-
-void
-evas_software_ddraw_surface_resize(DDraw_Output_Buffer *ddob)
-{
- DDSURFACEDESC surface_desc;
-
- ddob->dd.surface_back->Release();
- memset (&surface_desc, 0, sizeof (surface_desc));
- surface_desc.dwSize = sizeof (surface_desc);
- /* FIXME: that code does not compile. Must know why */
-#if 0
- surface_desc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
- surface_desc.dwWidth = width;
- surface_desc.dwHeight = height;
- IDirectDrawSurface7_SetSurfaceDesc(ddob->dd.surface_back, &surface_desc, NULL);
-#else
- surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
- surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
- surface_desc.dwWidth = ddob->width;
- surface_desc.dwHeight = ddob->height;
- ddob->dd.object->CreateSurface(&surface_desc, &ddob->dd.surface_back, NULL);
-#endif
-}
+++ /dev/null
-#include "evas_common.h"
-#include "evas_private.h"
-#include "evas_engine.h"
-#include "Evas_Engine_Software_16_DDraw.h"
-#include "evas_common_soft16.h"
-
-int _evas_engine_soft16_ddraw_log_dom = -1;
-/* function tables - filled in later (func and parent func) */
-static Evas_Func func, pfunc;
-
-/* engine struct data */
-typedef struct _Render_Engine Render_Engine;
-
-struct _Render_Engine
-{
- HWND window;
- LPDIRECTDRAW object;
- LPDIRECTDRAWSURFACE surface_primary;
- LPDIRECTDRAWSURFACE surface_back;
- LPDIRECTDRAWSURFACE surface_source;
- int width;
- int height;
- int rotation;
- Tilebuf *tb;
- Tilebuf_Rect *rects;
- Tilebuf_Rect *cur_rect;
- DDraw_Output_Buffer *ddob;
- Soft16_Image *tmp_out; /* used by indirect render, like rotation */
- HRGN clip_rects;
- unsigned char end : 1;
-};
-
-/* prototypes we will use here */
-
-static void *eng_info(Evas *e);
-static void eng_info_free(Evas *e, void *info);
-static int eng_setup(Evas *e, void *info);
-static void eng_output_free(void *data);
-static void eng_output_resize(void *data, int w, int h);
-static void eng_output_tile_size_set(void *data, int w, int h);
-static void eng_output_redraws_rect_add(void *data, int x, int y, int w, int h);
-static void eng_output_redraws_rect_del(void *data, int x, int y, int w, int h);
-static void eng_output_redraws_clear(void *data);
-static void *eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch);
-static void eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h);
-static void eng_output_flush(void *data);
-static void eng_output_idle_flush(void *data);
-
-/* engine api this module provides */
-static void *
-eng_info(Evas *e)
-{
- Evas_Engine_Info_Software_16_DDraw *info;
- info = calloc(1, sizeof(Evas_Engine_Info_Software_16_DDraw));
- if (!info) return NULL;
- info->magic.magic = rand();
- info->render_mode = EVAS_RENDER_MODE_BLOCKING;
- return info;
- e = NULL;
-}
-
-static void
-eng_info_free(Evas *e, void *info)
-{
- Evas_Engine_Info_Software_16_DDraw *in;
- in = (Evas_Engine_Info_Software_16_DDraw *)info;
- free(in);
-}
-
-static void
-_tmp_out_alloc(Render_Engine *re)
-{
- Tilebuf_Rect *r;
- int w = 0, h = 0;
-
- EINA_INLIST_FOREACH(re->rects, r)
- {
- if (r->w > w) w = r->w;
- if (r->h > h) h = r->h;
- }
-
- if (re->tmp_out)
- {
- if ((re->tmp_out->cache_entry.w < w) || (re->tmp_out->cache_entry.h < h))
- {
- evas_cache_image_drop(&re->tmp_out->cache_entry);
- re->tmp_out = NULL;
- }
- }
-
- if (!re->tmp_out)
- {
- Soft16_Image *im;
-
- im = (Soft16_Image *) evas_cache_image_empty(evas_common_soft16_image_cache_get());
- im->cache_entry.flags.alpha = 0;
- evas_cache_image_surface_alloc(&im->cache_entry, w, h);
-
- re->tmp_out = im;
- }
-}
-
-
-static int
-eng_setup(Evas *e, void *in)
-{
- Render_Engine *re;
- Evas_Engine_Info_Software_16_DDraw *info;
-
- info = (Evas_Engine_Info_Software_16_DDraw *)in;
- if (!e->engine.data.output)
- {
- /* the only check - simplistic, i know, but enough for this
- * "special purpose" engine. Remember it is meant to be used
- * for limited power devices that have a 16bit display mode
- * and no real other acceleration, and high resolution so we
- * can pre-dither into 16bpp. */
- if (info->info.depth != 16)
- return 0;
- /* do common routine init - we wil at least use it for core
- * image loading and font loading/glyph rendering & placement */
- evas_common_cpu_init();
-
- evas_common_blend_init();
- evas_common_image_init();
- evas_common_convert_init();
- evas_common_scale_init();
- evas_common_rectangle_init();
- evas_common_polygon_init();
- evas_common_line_init();
- evas_common_font_init();
- evas_common_draw_init();
- evas_common_tilebuf_init();
- evas_common_soft16_image_init();
-
- /* render engine specific data */
- re = calloc(1, sizeof(Render_Engine));
- if (!re)
- return 0;
- e->engine.data.output = re;
- re->window = info->info.window;
- re->object = info->info.object;
- re->surface_primary = info->info.surface_primary;
- re->surface_back = info->info.surface_back;
- re->surface_source = info->info.surface_source;
- re->width = e->output.w;
- re->height = e->output.h;
- re->rotation = info->info.rotation;
- re->tb = evas_common_tilebuf_new(e->output.w, e->output.h);
- if (re->tb)
- evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
- }
- else
- {
- /* we changed the info after first init - do a re-eval where
- * appropriate */
- if (info->info.depth != 16)
- return 0;
- re = e->engine.data.output;
- if (re->tb) evas_common_tilebuf_free(re->tb);
- re->window = info->info.window;
- re->object = info->info.object;
- re->surface_primary = info->info.surface_primary;
- re->surface_back = info->info.surface_back;
- re->surface_source = info->info.surface_source;
- re->width = e->output.w;
- re->height = e->output.h;
- re->rotation = info->info.rotation;
- re->tb = evas_common_tilebuf_new(e->output.w, e->output.h);
- if (re->tb)
- evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
- if (re->tmp_out)
- {
- evas_cache_image_drop(&re->tmp_out->cache_entry);
- re->tmp_out = NULL;
- }
- }
- if (!e->engine.data.output) return 0;
- /* add a draw context if we dont have one */
- if (!e->engine.data.context)
- e->engine.data.context =
- e->engine.func->context_new(e->engine.data.output);
-
- return 1;
-}
-
-static void
-eng_output_free(void *data)
-{
- Render_Engine *re;
-
- re = (Render_Engine *)data;
- if (re->ddob) evas_software_ddraw_output_buffer_free(re->ddob, 0);
- if (re->clip_rects) DeleteObject(re->clip_rects);
- if (re->tb) evas_common_tilebuf_free(re->tb);
- if (re->rects) evas_common_tilebuf_free_render_rects(re->rects);
- if (re->tmp_out) evas_cache_image_drop(&re->tmp_out->cache_entry);
- free(re);
-
- evas_common_font_shutdown();
- evas_common_image_shutdown();
- evas_common_soft16_image_shutdown();
-}
-
-static void
-eng_output_resize(void *data, int w, int h)
-{
- Render_Engine *re;
-
- re = (Render_Engine *)data;
-
- if ((re->width == w) && (re->height == h)) return;
-
- if (re->ddob)
- evas_software_ddraw_surface_resize(re->ddob);
-
- evas_common_tilebuf_free(re->tb);
- re->width = w;
- re->height = h;
- re->tb = evas_common_tilebuf_new(w, h);
- if (re->tb)
- evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
- if (re->ddob)
- {
- evas_software_ddraw_output_buffer_free(re->ddob, 0);
- re->ddob = NULL;
- }
- if (re->clip_rects)
- {
- DeleteObject(re->clip_rects);
- re->clip_rects = NULL;
- }
- if (re->tmp_out)
- {
- evas_cache_image_drop(&re->tmp_out->cache_entry);
- re->tmp_out = NULL;
- }
-}
-
-static void
-eng_output_tile_size_set(void *data, int w, int h)
-{
- Render_Engine *re;
-
- re = (Render_Engine *)data;
- evas_common_tilebuf_set_tile_size(re->tb, w, h);
-}
-
-static void
-eng_output_redraws_rect_add(void *data, int x, int y, int w, int h)
-{
- Render_Engine *re;
-
- re = (Render_Engine *)data;
- evas_common_tilebuf_add_redraw(re->tb, x, y, w, h);
-}
-
-static void
-eng_output_redraws_rect_del(void *data, int x, int y, int w, int h)
-{
- Render_Engine *re;
-
- re = (Render_Engine *)data;
- evas_common_tilebuf_del_redraw(re->tb, x, y, w, h);
-}
-
-static void
-eng_output_redraws_clear(void *data)
-{
- Render_Engine *re;
-
- re = (Render_Engine *)data;
- evas_common_tilebuf_clear(re->tb);
-}
-
-static inline void
-_output_buffer_alloc(Render_Engine *re)
-{
- int width;
- int height;
-
- if (re->ddob) return;
-
- if ((re->rotation == 0) || (re->rotation == 180))
- {
- width = re->width;
- height = re->height;
- }
- else
- {
- width = re->height;
- height = re->width;
- }
-
- re->ddob = evas_software_ddraw_output_buffer_new(re->window,
- re->object,
- re->surface_primary,
- re->surface_back,
- re->surface_source,
- width,
- height);
-}
-
-static void *
-eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch)
-{
- Render_Engine *re;
- Tilebuf_Rect *rect;
- int ux, uy, uw, uh;
-
- re = (Render_Engine *)data;
- if (re->end)
- {
- re->end = 0;
- return NULL;
- }
- if (!re->rects)
- {
- re->rects = evas_common_tilebuf_get_render_rects(re->tb);
- if (!re->rects) return NULL;
-
- re->cur_rect = re->rects;
- _output_buffer_alloc(re);
- if (re->rotation != 0) _tmp_out_alloc(re); /* grows if required */
- }
- if (!re->cur_rect)
- {
- if (re->rects) evas_common_tilebuf_free_render_rects(re->rects);
- re->rects = NULL;
- return NULL;
- }
- rect = re->cur_rect;
- ux = rect->x; uy = rect->y; uw = rect->w; uh = rect->h;
- re->cur_rect = (Tilebuf_Rect *)((EINA_INLIST_GET(re->cur_rect))->next);
- if (!re->cur_rect)
- {
- evas_common_tilebuf_free_render_rects(re->rects);
- re->rects = NULL;
- re->end = 1;
- }
-
- *x = ux; *y = uy; *w = uw; *h = uh;
- if (re->rotation == 0)
- {
- *cx = ux; *cy = uy; *cw = uw; *ch = uh;
- return &re->ddob->im;
- }
- else
- {
- *cx = 0; *cy = 0; *cw = uw; *ch = uh;
- return re->tmp_out;
- }
-}
-
-static void
-_blit_rot_90(Soft16_Image *dst, const Soft16_Image *src,
- int out_x, int out_y, int w, int h)
-{
- DATA16 *dp, *sp;
- int x, y;
-
- sp = src->pixels;
- dp = dst->pixels + (out_x +
- (w + out_y - 1) * dst->stride);
-
- for (y = 0; y < h; y++)
- {
- DATA16 *dp_itr, *sp_itr;
-
- sp_itr = sp;
- dp_itr = dp;
-
- for (x = 0; x < w; x++)
- {
- *dp_itr = *sp_itr;
-
- sp_itr++;
- dp_itr -= dst->stride;
- }
- sp += src->stride;
- dp++;
- }
-}
-
-static void
-_blit_rot_180(Soft16_Image *dst, const Soft16_Image *src,
- int out_x, int out_y, int w, int h)
-{
- DATA16 *dp, *sp;
- int x, y;
-
- sp = src->pixels;
- dp = dst->pixels + ((w + out_x - 1) +
- (h + out_y - 1) * dst->stride);
-
- for (y = 0; y < h; y++)
- {
- DATA16 *dp_itr, *sp_itr;
-
- sp_itr = sp;
- dp_itr = dp;
-
- for (x = 0; x < w; x++)
- {
- *dp_itr = *sp_itr;
-
- sp_itr++;
- dp_itr--;
- }
- sp += src->stride;
- dp -= dst->stride;
- }
-}
-
-static void
-_blit_rot_270(Soft16_Image *dst, const Soft16_Image *src,
- int out_x, int out_y, int w, int h)
-{
- DATA16 *dp, *sp;
- int x, y;
-
- sp = src->pixels;
- dp = dst->pixels + ((h + out_x - 1) +
- out_y * dst->stride);
-
- for (y = 0; y < h; y++)
- {
- DATA16 *dp_itr, *sp_itr;
-
- sp_itr = sp;
- dp_itr = dp;
-
- for (x = 0; x < w; x++)
- {
- *dp_itr = *sp_itr;
-
- sp_itr++;
- dp_itr += dst->stride;
- }
- sp += src->stride;
- dp--;
- }
-}
-
-static void
-_tmp_out_process(Render_Engine *re, int out_x, int out_y, int w, int h)
-{
- Soft16_Image *d, *s;
-
- d = &re->ddob->im;
- s = re->tmp_out;
-
- if ((w < 1) || (h < 1) || (out_x >= d->cache_entry.w) || (out_y >= d->cache_entry.h))
- return;
-
- if (re->rotation == 90)
- _blit_rot_90(d, s, out_x, out_y, w, h);
- else if (re->rotation == 180)
- _blit_rot_180(d, s, out_x, out_y, w, h);
- else if (re->rotation == 270)
- _blit_rot_270(d, s, out_x, out_y, w, h);
-}
-
-static void
-eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h)
-{
- Render_Engine *re;
- HRGN region;
- int xx;
- int yy;
- int width;
- int height;
-
- re = (Render_Engine *)data;
-
- if (!re->clip_rects)
- re->clip_rects = CreateRectRgn(0, 0, 0, 0);
-
- if (re->rotation == 0)
- {
- xx = x;
- yy = y;
- width = w;
- height = h;
- }
- else if (re->rotation == 90)
- {
- xx = y;
- yy = re->width - w - x;
- width = h;
- height = w;
- }
- else if (re->rotation == 180)
- {
- xx = re->width - w - x;
- yy = re->height - h - y;
- width = w;
- height = h;
- }
- else if (re->rotation == 270)
- {
- xx = re->height - h - y;
- yy = x;
- width = h;
- height = w;
- }
-
- region = CreateRectRgn(xx, yy, xx + width, yy + height);
-
- if (re->rotation != 0)
- _tmp_out_process(re, xx, yy, w, h);
- CombineRgn(re->clip_rects, re->clip_rects, region, RGN_OR);
-}
-
-static void
-eng_output_flush(void *data)
-{
- Render_Engine *re;
- void *ddraw_data;
- int ddraw_width;
- int ddraw_height;
- int ddraw_pitch;
- int ddraw_depth;
-
- re = (Render_Engine *)data;
- if (re->clip_rects)
- {
- /* FIXME : i have to manage that */
-/* XSetRegion(re->disp, re->gc, re->clip_rects); */
- DeleteObject(re->clip_rects);
- re->clip_rects = NULL;
- }
- else return;
-
- evas_software_ddraw_output_buffer_paste(re->ddob);
-
- /* FIXME : i have to manage that */
-/* XSetClipMask(re->disp, re->gc, None); */
-}
-
-static void
-eng_output_idle_flush(void *data)
-{
- Render_Engine *re;
-
- re = (Render_Engine *)data;
- if (re->ddob)
- {
- evas_software_ddraw_output_buffer_free(re->ddob, 0);
- re->ddob = NULL;
- }
- if (re->clip_rects)
- {
- DeleteObject(re->clip_rects);
- re->clip_rects = NULL;
- }
- if (re->tmp_out)
- {
- evas_cache_image_drop(&re->tmp_out->cache_entry);
- re->tmp_out = NULL;
- }
-}
-
-static Eina_Bool
-eng_canvas_alpha_get(void *data, void *context)
-{
- return EINA_FALSE;
-}
-
-/* module advertising code */
-static int
-module_open(Evas_Module *em)
-{
- if (!em) return 0;
- /* get whatever engine module we inherit from */
- if (!_evas_module_engine_inherit(&pfunc, "software_16")) return 0;
- _evas_engine_soft16_ddraw_log_dom = eina_log_domain_register
- ("evas-software_16_ddraw", EVAS_DEFAULT_LOG_COLOR);
- if (_evas_engine_soft16_ddraw_log_dom < 0)
- {
- EINA_LOG_ERR("Can not create a module log domain.");
- return 0;
- }
- /* store it for later use */
- func = pfunc;
- /* now to override methods */
-#define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_)
- ORD(info);
- ORD(info_free);
- ORD(setup);
- ORD(canvas_alpha_get);
- ORD(output_free);
- ORD(output_resize);
- ORD(output_tile_size_set);
- ORD(output_redraws_rect_add);
- ORD(output_redraws_rect_del);
- ORD(output_redraws_clear);
- ORD(output_redraws_next_update_get);
- ORD(output_redraws_next_update_push);
- ORD(output_flush);
- ORD(output_idle_flush);
- /* now advertise out own api */
- em->functions = (void *)(&func);
- return 1;
-}
-
-static void
-module_close(Evas_Module *em)
-{
- eina_log_domain_unregister(_evas_engine_soft16_ddraw_log_dom);
-}
-
-static Evas_Module_Api evas_modapi =
-{
- EVAS_MODULE_API_VERSION,
- "software_16_ddraw",
- "none",
- {
- module_open,
- module_close
- }
-};
-
-EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, software_16_ddraw);
-
-#ifndef EVAS_STATIC_BUILD_SOFTWARE_16_DDRAW
-EVAS_EINA_MODULE_DEFINE(engine, software_16_ddraw);
-#endif
+++ /dev/null
-#ifndef __EVAS_ENGINE_H__
-#define __EVAS_ENGINE_H__
-
-#include <windows.h>
-#include <ddraw.h>
-
-#include "evas_common_soft16.h"
-
-extern int _evas_engine_soft16_ddraw_log_dom ;
-#ifdef ERR
-# undef ERR
-#endif
-#define ERR(...) EINA_LOG_DOM_ERR(_evas_engine_soft16_ddraw_log_dom, __VA_ARGS__)
-
-#ifdef DBG
-# undef DBG
-#endif
-#define DBG(...) EINA_LOG_DOM_DBG(_evas_engine_soft16_ddraw_log_dom, __VA_ARGS__)
-
-#ifdef INF
-# undef INF
-#endif
-#define INF(...) EINA_LOG_DOM_INFO(_evas_engine_soft16_ddraw_log_dom, __VA_ARGS__)
-
-#ifdef WRN
-# undef WRN
-#endif
-#define WRN(...) EINA_LOG_DOM_WARN(_evas_engine_soft16_ddraw_log_dom, __VA_ARGS__)
-
-#ifdef CRIT
-# undef CRIT
-#endif
-#define CRIT(...) EINA_LOG_DOM_CRIT(_evas_engine_soft16_ddraw_log_dom, __VA_ARGS__)
-
-typedef struct _DDraw_Output_Buffer DDraw_Output_Buffer;
-
-struct _DDraw_Output_Buffer
-{
- Soft16_Image *im;
- struct {
- HWND window;
- LPDIRECTDRAW object;
- LPDIRECTDRAWSURFACE surface_primary;
- LPDIRECTDRAWSURFACE surface_back;
- LPDIRECTDRAWSURFACE surface_source;
- } dd;
- void *data;
- int x;
- int y;
- int width;
- int height;
- int depth;
- int pitch;
-};
-
-/****/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-DDraw_Output_Buffer *evas_software_ddraw_output_buffer_new (HWND window,
- LPDIRECTDRAW object,
- LPDIRECTDRAWSURFACE surface_primary,
- LPDIRECTDRAWSURFACE surface_back,
- LPDIRECTDRAWSURFACE surface_source,
- int width,
- int height);
-void evas_software_ddraw_output_buffer_free (DDraw_Output_Buffer *ddob, int sync);
-void evas_software_ddraw_output_buffer_paste (DDraw_Output_Buffer *ddob);
-
-
-void *evas_software_ddraw_lock(DDraw_Output_Buffer *ddob, int *ddraw_width, int *ddraw_height, int *ddraw_pitch, int *ddraw_depth);
-
-void evas_software_ddraw_unlock_and_flip(DDraw_Output_Buffer *ddob);
-
-void evas_software_ddraw_surface_resize(DDraw_Output_Buffer *ddob);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __EVAS_ENGINE_H__ */
}
static Evas_Font_Set *
-eng_font_memory_load(void *data __UNUSED__, char *name, int size, const void *fdata, int fdata_size, Font_Rend_Flags wanted_rend)
+eng_font_memory_load(void *data __UNUSED__, const char *source, const char *name, int size, const void *fdata, int fdata_size, Font_Rend_Flags wanted_rend)
{
- return (Evas_Font_Set *) evas_common_font_memory_load(name, size, fdata,
- fdata_size, wanted_rend);
+ return (Evas_Font_Set *) evas_common_font_memory_load(source, name, size,
+ fdata, fdata_size, wanted_rend);
}
static Evas_Font_Set *
}
static Evas_Font_Set *
-eng_font_memory_add(void *data __UNUSED__, Evas_Font_Set *font, char *name, int size, const void *fdata, int fdata_size, Font_Rend_Flags wanted_rend)
+eng_font_memory_add(void *data __UNUSED__, Evas_Font_Set *font, const char *source, const char *name, int size, const void *fdata, int fdata_size, Font_Rend_Flags wanted_rend)
{
return (Evas_Font_Set *) evas_common_font_memory_add((RGBA_Font *) font,
- name, size, fdata, fdata_size, wanted_rend);
+ source, name, size, fdata, fdata_size, wanted_rend);
}
static void
/* if we already have a window surface, check for NULL input surface.
* this will mean we are hiding the window and should destroy
* things properly */
- if ((re->win->surface) && (re->info->info.surface = NULL))
+ if ((re->win->surface) && (re->info->info.surface == NULL))
{
if (re->win)
{
evas_textblock_cursor_paragraph_first(cur);
fail_if(evas_textblock_cursor_paragraph_next(cur));
+ {
+ /* Limit to 1000 iterations so we'll never get into an infinite loop,
+ * even if broken */
+ int limit = 1000;
+ evas_object_textblock_text_markup_set(tb, "this is a test eauoeuaou<ps/>this is a test1<ps/>this is a test 3");
+ evas_textblock_cursor_paragraph_last(cur);
+ while (evas_textblock_cursor_pos_get(cur) > 0)
+ {
+ limit--;
+ fail_if(limit <= 0);
+ evas_textblock_cursor_copy(cur, main_cur);
+ evas_textblock_cursor_char_prev(cur);
+ evas_textblock_cursor_word_start(cur);
+ evas_textblock_cursor_range_delete(cur, main_cur);
+ }
+ }
+
+
/* Insert illegal characters inside the format. */
{
const char *content;