Revert "Revert "upstream merge""
authorJaehwan Kim <jae.hwan.kim@samsung.com>
Tue, 14 Aug 2012 11:17:23 +0000 (20:17 +0900)
committerJaehwan Kim <jae.hwan.kim@samsung.com>
Tue, 14 Aug 2012 11:17:23 +0000 (20:17 +0900)
This reverts commit 9a680a724ae10baa8bfdccfae5d648afd6fb64c6.

Conflicts:

ChangeLog
NEWS

53 files changed:
.gitignore
Makefile.am
configure.ac
evas-software-16-ddraw.pc.in [deleted file]
m4/evas_check_engine.m4
packaging/evas.spec
src/bin/Makefile.am
src/bin/dummy_slave.c
src/bin/evas_cserve2.h
src/bin/evas_cserve2_cache.c
src/bin/evas_cserve2_client.c
src/bin/evas_cserve2_debug.c [new file with mode: 0644]
src/bin/evas_cserve2_fonts.c
src/bin/evas_cserve2_main.c
src/bin/evas_cserve2_main_loop_linux.c
src/bin/evas_cserve2_requests.c
src/bin/evas_cserve2_shm.c
src/bin/evas_cserve2_slave.c
src/bin/evas_cserve2_slaves.c
src/bin/evas_cserve2_usage.c [new file with mode: 0644]
src/lib/Evas.h
src/lib/Makefile.am
src/lib/canvas/evas_font_dir.c
src/lib/canvas/evas_object_textblock.c
src/lib/canvas/evas_object_textgrid.c
src/lib/cserve2/Makefile.am
src/lib/cserve2/evas_cs2.h
src/lib/cserve2/evas_cs2_client.c
src/lib/cserve2/evas_cs2_private.h
src/lib/cserve2/evas_cs2_utils.c [new file with mode: 0644]
src/lib/cserve2/evas_cs2_utils.h [new file with mode: 0644]
src/lib/engines/common/evas_font.h
src/lib/engines/common/evas_font_default_walk.x
src/lib/engines/common/evas_font_draw.c
src/lib/engines/common/evas_font_load.c
src/lib/engines/common/evas_font_main.c
src/lib/engines/common/evas_font_query.c
src/lib/engines/common/evas_text_utils.c
src/lib/engines/common/evas_text_utils.h
src/lib/file/evas_module.c
src/lib/include/evas_common.h
src/lib/include/evas_private.h
src/modules/engines/Makefile.am
src/modules/engines/gl_x11/evas_x_main.c
src/modules/engines/software_16_ddraw/Evas_Engine_Software_16_DDraw.h [deleted file]
src/modules/engines/software_16_ddraw/Makefile.am [deleted file]
src/modules/engines/software_16_ddraw/evas_ddraw_buffer.cpp [deleted file]
src/modules/engines/software_16_ddraw/evas_ddraw_main.cpp [deleted file]
src/modules/engines/software_16_ddraw/evas_engine.c [deleted file]
src/modules/engines/software_16_ddraw/evas_engine.h [deleted file]
src/modules/engines/software_generic/evas_engine.c
src/modules/engines/wayland_egl/evas_engine.c
src/tests/evas_test_textblock.c

index e047c2d..b46dd18 100755 (executable)
@@ -43,7 +43,9 @@ src/bin/evas_cserve
 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
index 10686e2..d8cb45a 100644 (file)
@@ -40,7 +40,6 @@ evas-software-16-x11.pc.in \
 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 \
@@ -109,10 +108,6 @@ if BUILD_ENGINE_SOFTWARE_DDRAW
 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
index 93e26ed..3c03548 100644 (file)
@@ -101,7 +101,6 @@ want_evas_engine_software_gdi="no"
 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"
@@ -146,7 +145,6 @@ case "$host_os" in
       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"
       ;;
@@ -382,7 +380,7 @@ AC_ARG_ENABLE([harfbuzz],
 
 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}"
@@ -766,8 +764,6 @@ EVAS_CHECK_ENGINE([software-8-x11], [${want_evas_engine_software_8_x11}], [no],
 
 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])
@@ -977,9 +973,6 @@ fi
 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
@@ -1890,7 +1883,6 @@ evas-software-8-x11.pc
 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
@@ -1952,7 +1944,6 @@ src/modules/engines/software_8/Makefile
 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
@@ -2048,7 +2039,6 @@ echo "  Software 8bit grayscale....: $have_evas_engine_software_8"
 # 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"
diff --git a/evas-software-16-ddraw.pc.in b/evas-software-16-ddraw.pc.in
deleted file mode 100644 (file)
index 8c00f61..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Name: evas-software-16-ddraw
-Description: Evas 16bit software DirectDaw engine
-Version: @VERSION@
index 6275795..a0e1dfe 100644 (file)
@@ -764,33 +764,6 @@ fi
 
 ])
 
-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],
index b5a7849..73e598b 100755 (executable)
@@ -1,7 +1,7 @@
 #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
@@ -113,6 +113,8 @@ rm -rf %{buildroot}
 %{_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
index 815defc..6cddccd 100644 (file)
@@ -45,7 +45,7 @@ if EVAS_CSERVE2
 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. \
@@ -56,7 +56,8 @@ AM_CPPFLAGS = \
 -DPACKAGE_LIB_DIR=\"$(libdir)\" \
 -DPACKAGE_LIBEXEC_DIR=\"$(libexecdir)\" \
 @FREETYPE_CFLAGS@ \
-@EINA_CFLAGS@
+@EINA_CFLAGS@ \
+@EET_CFLAGS@
 
 evas_cserve2_SOURCES = \
 evas_cserve2.h \
@@ -70,14 +71,30 @@ evas_cserve2_requests.c \
 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
index a150d67..398d86e 100644 (file)
@@ -89,8 +89,8 @@ error_send(int fd, Error_Type err)
    return response_send(fd, ERROR, &err, sizeof(Error_Type));
 }
 
-void *
-cserve2_shm_map(const char *name, size_t length, off_t offset)
+static void *
+_cserve2_shm_map(const char *name, size_t length, off_t offset)
 {
    void *map;
    int fd;
@@ -106,11 +106,13 @@ cserve2_shm_map(const char *name, size_t length, off_t offset)
    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)
@@ -128,8 +130,8 @@ image_open(const char *file __UNUSED__, const char *key __UNUSED__, Slave_Msg_Im
 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;
 
index a1008ac..98c6547 100644 (file)
@@ -21,6 +21,8 @@
 #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;
@@ -119,11 +121,12 @@ struct _Slave_Msg_Font_Load {
    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 {
@@ -131,11 +134,58 @@ 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);
 
@@ -161,6 +211,8 @@ typedef enum {
    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? */
@@ -211,6 +263,9 @@ off_t cserve2_shm_map_offset_get(const Shm_Handle *shm);
 off_t cserve2_shm_offset_get(const Shm_Handle *shm);
 size_t cserve2_shm_map_size_get(const Shm_Handle *shm);
 size_t cserve2_shm_size_get(const Shm_Handle *shm);
+void *cserve2_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);
 
@@ -225,10 +280,16 @@ void cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsi
 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);
@@ -240,5 +301,7 @@ void cserve2_cache_requests_response(Slave_Command type, void *msg, void *data);
 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 */
index 0cc4d87..12fdec3 100644 (file)
@@ -4,7 +4,12 @@
 
 #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;
@@ -19,7 +24,6 @@ typedef struct _File_Watch File_Watch;
 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);
@@ -49,6 +53,12 @@ struct _Entry {
    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 {
@@ -85,6 +95,7 @@ struct _Image_Data {
 };
 
 struct _Font_Source {
+   const char *key;
    const char *name;
    const char *file;
    int references;
@@ -95,32 +106,69 @@ struct _Font_Entry {
    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;
@@ -158,8 +206,55 @@ static Eina_Hash *file_watch = NULL;
 
 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)
@@ -237,13 +332,15 @@ _image_preloaded_send(Client *client, 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;
 
@@ -272,6 +369,9 @@ _open_request_build(File_Data *f, int *bufsize)
    memcpy(buf + sizeof(msg) + pathlen, f->key, keylen);
 
    *bufsize = size;
+
+   _entry_load_start(&f->base);
+
    return buf;
 }
 
@@ -310,6 +410,7 @@ _open_request_response(File_Data *e, Slave_Msg_Image_Opened *resp)
 {
    Waiter *w;
 
+   _entry_load_finish(&e->base);
    e->w = resp->w;
    e->h = resp->h;
    e->frame_count = resp->frame_count;
@@ -397,6 +498,9 @@ _load_request_build(Image_Data *i, int *bufsize)
    memcpy(ptr, i->file->loader_data, loaderlen);
 
    *bufsize = size;
+
+   _entry_load_start(&i->base);
+
    return buf;
 }
 
@@ -405,6 +509,8 @@ _load_request_response(Image_Data *e, Slave_Msg_Image_Loaded *resp)
 {
    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);
@@ -503,7 +609,11 @@ _image_entry_free(Image_Data *entry)
      }
 
    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);
@@ -581,28 +691,24 @@ _file_watch_free(void *data)
 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));
@@ -613,18 +719,100 @@ _font_entry_key_hash(const Font_Entry *key, int key_length __UNUSED__)
 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)
 {
@@ -645,6 +833,11 @@ 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);
@@ -893,13 +1086,10 @@ _entry_reference_del(Entry *entry, Reference *ref)
 
         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)
      {
@@ -915,7 +1105,9 @@ _entry_reference_del(Entry *entry, Reference *ref)
    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.");
@@ -955,11 +1147,25 @@ _entry_free_cb(void *data)
 }
 
 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
@@ -982,7 +1188,7 @@ cserve2_cache_client_del(Client *client)
 
    EINA_LIST_FREE(client->fonts.referencing, ref)
      {
-        _font_entry_reference_del(client, ref);
+        _entry_reference_del(ref->entry, ref);
      }
 }
 
@@ -1082,21 +1288,20 @@ _cserve2_font_source_find(const char *name)
 }
 
 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;
 }
@@ -1110,7 +1315,6 @@ _font_load_request_build(void *data, int *size)
    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;
@@ -1118,33 +1322,50 @@ _font_load_request_build(void *data, int *size)
 
    *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 = {
@@ -1154,6 +1375,729 @@ 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)
 {
@@ -1168,6 +2112,7 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char
    if (ref)
      {
         entry = (File_Data *)ref->entry;
+        _entry_load_reused(ref->entry);
 
         if (entry->invalid)
           {
@@ -1188,7 +2133,7 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char
 
    // 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",
@@ -1202,6 +2147,7 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char
              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);
@@ -1222,7 +2168,7 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char
    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);
 
@@ -1300,6 +2246,7 @@ cserve2_cache_image_opts_set(Client *client, Msg_Setopts *msg)
              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;
@@ -1320,7 +2267,7 @@ cserve2_cache_image_opts_set(Client *client, Msg_Setopts *msg)
 
    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)
@@ -1445,50 +2392,167 @@ 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)
+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;
 }
 
@@ -1522,3 +2586,36 @@ cserve2_cache_requests_response(Slave_Command type, void *msg, void *data)
      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);
+}
index d8add9c..b2a33ac 100644 (file)
@@ -11,7 +11,6 @@
 
 #include "evas_cserve2.h"
 
-static const char *SOCK_PATH = "/tmp/cserve2.socket";
 static unsigned int _rid_count = 0;
 
 static struct sockaddr_un socket_local;
diff --git a/src/bin/evas_cserve2_debug.c b/src/bin/evas_cserve2_debug.c
new file mode 100644 (file)
index 0000000..c86045c
--- /dev/null
@@ -0,0 +1,451 @@
+#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();
+}
index 36dc140..3a1cff5 100644 (file)
@@ -2,23 +2,49 @@
 # 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
@@ -26,11 +52,11 @@ 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)
 {
@@ -40,29 +66,80 @@ _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;
 }
@@ -79,46 +156,55 @@ _font_slave_int_load(const Slave_Msg_Font_Load *msg, Font_Source_Info *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;
+                    }
+               }
           }
      }
 
@@ -159,11 +245,12 @@ _font_slave_load(const void *cmddata, void *data __UNUSED__)
    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)
@@ -175,8 +262,8 @@ _font_slave_load(const void *cmddata, void *data __UNUSED__)
    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;
      }
 
@@ -187,6 +274,241 @@ _font_slave_load(const void *cmddata, void *data __UNUSED__)
    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)
 {
@@ -198,7 +520,7 @@ cserve2_font_slave_cb(Slave_Thread_Data *sd __UNUSED__, Slave_Command *cmd, cons
          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);
@@ -224,6 +546,10 @@ cserve2_font_init(void)
 
    error = FT_Init_FreeType(&cserve2_ft_lib);
    if (error) return;
+
+#ifdef BUILD_FONT_LOADER_EET
+   eet_init();
+#endif
 }
 
 void
@@ -239,4 +565,27 @@ cserve2_font_shutdown(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);
 }
index 582fbe0..a9fc1eb 100644 (file)
@@ -33,13 +33,6 @@ static Eina_Hash *client_list = NULL;
 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)
 {
@@ -154,6 +147,7 @@ cserve2_slave_cmd_dispatch(void *data, Slave_Command cmd, const void *msg, int s
                                             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;
@@ -270,52 +264,81 @@ static void
 _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)
 {
@@ -347,6 +370,12 @@ 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");
      }
index e8cc33d..6063925 100644 (file)
@@ -26,6 +26,7 @@ struct _Watch_Data
    Fd_Flags flags;
    Fd_Watch_Cb callback;
    const void *user_data;
+   Eina_Bool deleted : 1;
 };
 
 typedef struct _Watch_Data Watch_Data;
@@ -47,6 +48,7 @@ static int socket_fd = -1;
 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;
@@ -354,7 +356,9 @@ _inotifyfd_finish(void)
 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
@@ -444,6 +448,8 @@ error_socket:
 void
 cserve2_main_loop_finish(void)
 {
+   Watch_Data *wd;
+
    _socketfd_finish();
 
    _signalfd_finish();
@@ -451,6 +457,8 @@ cserve2_main_loop_finish(void)
    _inotifyfd_finish();
 
    eina_hash_free(watch_list);
+   EINA_LIST_FREE(deleted_watch_list, wd)
+     free(wd);
 
    close(epoll_fd);
 }
@@ -726,6 +734,7 @@ cserve2_main_loop_run(void)
      {
         struct epoll_event events[MAX_EPOLL_EVENTS];
         int n, nfds;
+        Watch_Data *data;
 
         if (terminate)
           break;
@@ -748,12 +757,15 @@ cserve2_main_loop_run(void)
 
         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;
 
@@ -766,6 +778,9 @@ cserve2_main_loop_run(void)
              data->callback(data->fd, flags, (void *)data->user_data);
           }
 
+        EINA_LIST_FREE(deleted_watch_list, data)
+          free(data);
+
         _update_timeout();
      }
 
index ebff692..11a2e0b 100644 (file)
@@ -40,7 +40,7 @@ static struct _Request_Match
 {
    { 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);
@@ -81,7 +81,7 @@ typedef struct _Waiter Waiter;
 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;
@@ -89,6 +89,8 @@ 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)
 {
@@ -103,21 +105,23 @@ _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)
@@ -130,23 +134,34 @@ cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Fo
           }
      }
 
+   /* 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;
@@ -167,13 +182,13 @@ cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err)
 
    // 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);
      }
 
@@ -195,9 +210,12 @@ cserve2_request_cancel_all(Font_Request *req, Error_Type err)
         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);
 }
 
@@ -226,7 +244,7 @@ _cserve2_request_failed(Font_Request *req, Error_Type type)
         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);
@@ -252,7 +270,7 @@ _slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
         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);
@@ -265,6 +283,8 @@ _slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
    idle = &_workers[sw->type].idle;
    *working = eina_list_remove(*working, sw);
    *idle = eina_list_append(*idle, sw);
+
+   _cserve2_requests_process();
 }
 
 static void
@@ -338,6 +358,8 @@ _cserve2_request_dispatch(Slave_Worker *sw, Slave_Command ctype, Font_Request *r
    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);
@@ -352,10 +374,10 @@ _cserve2_request_dispatch(Slave_Worker *sw, Slave_Command ctype, Font_Request *r
    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++)
       {
@@ -366,7 +388,7 @@ cserve2_requests_process(void)
 
          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;
@@ -387,7 +409,7 @@ cserve2_requests_process(void)
          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;
index 36291f9..5e60138 100644 (file)
@@ -27,10 +27,30 @@ struct _Shm_Handle
    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)
 {
@@ -38,7 +58,6 @@ 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));
@@ -59,14 +78,7 @@ cserve2_shm_request(size_t size)
           }
    } 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)
      {
@@ -106,6 +118,9 @@ cserve2_shm_unref(Shm_Handle *shm)
    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)
@@ -145,3 +160,36 @@ cserve2_shm_size_get(const Shm_Handle *shm)
 {
    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;
+}
index b6e4610..a11c635 100644 (file)
@@ -187,8 +187,8 @@ error_send(int fd, Error_Type err)
    return response_send(fd, ERROR, &err, sizeof(Error_Type));
 }
 
-void *
-cserve2_shm_map(const char *name, size_t length, off_t offset)
+static void *
+_cserve2_shm_map(const char *name, size_t length, off_t offset)
 {
    void *map;
    int fd;
@@ -204,8 +204,8 @@ cserve2_shm_map(const char *name, size_t length, off_t offset)
    return map;
 }
 
-void
-cserve2_shm_unmap(void *map, size_t length)
+static void
+_cserve2_shm_unmap(void *map, size_t length)
 {
    munmap(map, length);
 }
@@ -316,8 +316,8 @@ image_load(const char *file, const char *key, const char *shmfile, Slave_Msg_Ima
    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;
 
@@ -352,7 +352,7 @@ image_load(const char *file, const char *key, const char *shmfile, Slave_Msg_Ima
    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;
 }
index 36eff20..4a5d6ac 100644 (file)
@@ -470,7 +470,7 @@ _slave_thread_cb(void *data)
 
         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;
           }
diff --git a/src/bin/evas_cserve2_usage.c b/src/bin/evas_cserve2_usage.c
new file mode 100644 (file)
index 0000000..e8307e3
--- /dev/null
@@ -0,0 +1,244 @@
+#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();
+}
index c0e2068..b52a0a9 100644 (file)
@@ -9196,6 +9196,7 @@ struct _Evas_Textgrid_Cell
    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) */
 };
 
 /**
index 9d9f3a1..00511f3 100644 (file)
@@ -52,11 +52,6 @@ if EVAS_STATIC_BUILD_SOFTWARE_16
 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
index e97f7f7..aa0d9c3 100644 (file)
@@ -588,7 +588,7 @@ evas_font_load(Evas *evas, Evas_Font_Description *fdesc, const char *source, Eva
                                 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);
@@ -649,7 +649,7 @@ evas_font_load(Evas *evas, Evas_Font_Description *fdesc, const char *source, Eva
                                 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);
index 3f8a2c8..914a815 100644 (file)
@@ -7666,8 +7666,6 @@ evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_C
 
    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)))
           {
@@ -7681,12 +7679,8 @@ evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_C
              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, "");
@@ -7701,13 +7695,6 @@ evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_C
           }
         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
      {
@@ -9114,6 +9101,12 @@ evas_object_textblock_clear(Evas_Object *obj)
        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);
 }
 
index 7b001ac..b75d392 100644 (file)
@@ -17,6 +17,18 @@ typedef struct _Evas_Object_Textgrid_Row   Evas_Object_Textgrid_Row;
 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
 {
@@ -34,14 +46,26 @@ 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;
@@ -73,7 +97,7 @@ struct _Evas_Object_Textgrid_Text
 {
    unsigned char r, g, b, a;
    int x;
-   Evas_Text_Props text_props;
+   unsigned int text_props;
 };
 
 struct _Evas_Object_Textgrid_Line
@@ -127,6 +151,186 @@ static const Evas_Object_Func object_func =
 
 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)
@@ -161,13 +365,14 @@ evas_object_textgrid_new(void)
    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;
    
@@ -181,7 +386,11 @@ evas_object_textgrid_row_clear(Evas_Object_Textgrid_Row *r)
    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;
@@ -206,7 +415,7 @@ evas_object_textgrid_rows_clear(Evas_Object *obj)
    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;
      }
@@ -215,8 +424,8 @@ evas_object_textgrid_rows_clear(Evas_Object *obj)
 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);
@@ -232,12 +441,39 @@ evas_object_textgrid_free(Evas_Object *obj)
    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);
@@ -272,10 +508,6 @@ evas_object_textgrid_row_rect_append(Evas_Object_Textgrid_Row *row, int x, int w
 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)
      {
@@ -290,18 +522,8 @@ evas_object_textgrid_row_text_append(Evas_Object_Textgrid_Row *row, Evas_Object
           }
         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;
@@ -370,12 +592,13 @@ evas_object_textgrid_render(Evas_Object *obj, void *output, void *context, void
         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)
@@ -410,9 +633,10 @@ evas_object_textgrid_render(Evas_Object *obj, void *output, void *context, void
                }
              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,
@@ -421,13 +645,13 @@ evas_object_textgrid_render(Evas_Object *obj, void *output, void *context, void
                        // 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;
@@ -462,7 +686,8 @@ evas_object_textgrid_render(Evas_Object *obj, void *output, void *context, void
                                      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++)
           {
@@ -471,7 +696,7 @@ evas_object_textgrid_render(Evas_Object *obj, void *output, void *context, void
                                      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;
      }
@@ -574,50 +799,8 @@ evas_object_textgrid_render_pre(Evas_Object *obj)
           }
         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)
           {
@@ -660,6 +843,26 @@ evas_object_textgrid_render_post(Evas_Object *obj)
    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
@@ -920,6 +1123,7 @@ evas_object_textgrid_font_set(Evas_Object *obj, const char *font_name, Evas_Font
         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,
@@ -932,6 +1136,11 @@ evas_object_textgrid_font_set(Evas_Object *obj, const char *font_name, Evas_Font
         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
@@ -966,6 +1175,27 @@ evas_object_textgrid_font_set(Evas_Object *obj, const char *font_name, Evas_Font
    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
@@ -1051,24 +1281,36 @@ evas_object_textgrid_palette_set(Evas_Object *obj, Evas_Textgrid_Palette pal, in
    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
@@ -1119,10 +1361,10 @@ evas_object_textgrid_palette_get(const Evas_Object *obj, Evas_Textgrid_Palette p
    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;
@@ -1237,7 +1479,7 @@ evas_object_textgrid_update_add(Evas_Object *obj, int x, int y, int w, int h)
         
         if (r->ch1 < 0)
           {
-             evas_object_textgrid_row_clear(r);
+             evas_object_textgrid_row_clear(o, r);
              r->ch1 = x;
              r->ch2 = x2;
           }
index 252899f..39d7048 100644 (file)
@@ -14,7 +14,7 @@ AM_CPPFLAGS = \
 
 if EVAS_CSERVE2
 
-noinst_LTLIBRARIES = libevas_cserve2.la
+noinst_LTLIBRARIES = libevas_cserve2.la libevas_cserve2_utils.la
 
 libevas_cserve2_la_SOURCES = \
 evas_cs2.h \
@@ -22,6 +22,10 @@ evas_cs2_private.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
index 77e7f8c..938ea5f 100644 (file)
@@ -22,6 +22,8 @@ typedef enum {
    CSERVE2_FONT_GLYPHS_LOAD,
    CSERVE2_FONT_GLYPHS_LOADED,
    CSERVE2_FONT_GLYPHS_USED,
+   CSERVE2_STATS,
+   CSERVE2_FONT_DEBUG,
    CSERVE2_ERROR
 } Message_Type;
 
@@ -127,9 +129,9 @@ struct _Msg_Close {
  */
 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
 };
@@ -146,18 +148,19 @@ struct _Msg_Font_Loaded {
 /**
  * @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;
 };
 
@@ -180,6 +183,12 @@ struct _Msg_Font_Glyphs_Request {
  *  - 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 {
@@ -187,6 +196,79 @@ 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;
@@ -206,6 +288,8 @@ typedef struct _Msg_Font_Load Msg_Font_Load;
 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
index 1b93ccd..97ccd8e 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "evas_cs2.h"
 #include "evas_cs2_private.h"
+#include "evas_cs2_utils.h"
 
 #ifdef EVAS_CSERVE2
 
@@ -130,15 +131,37 @@ _request_answer_add(Message_Type type, unsigned int rid, Op_Callback cb, void *d
 }
 
 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;
@@ -151,6 +174,8 @@ _server_send(const void *buf, int size, Op_Callback cb, void *data)
       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:
@@ -752,4 +777,507 @@ evas_cserve2_dispatch(void)
 {
    _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
index c0dde77..4373bfd 100644 (file)
@@ -18,6 +18,7 @@ struct _Data_Entry {
 };
 
 typedef struct _Data_Entry Data_Entry;
+typedef struct _Font_Entry Font_Entry;
 
 int evas_cserve2_init(void);
 int evas_cserve2_shutdown(void);
@@ -32,4 +33,10 @@ Eina_Bool evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(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
diff --git a/src/lib/cserve2/evas_cs2_utils.c b/src/lib/cserve2/evas_cs2_utils.c
new file mode 100644 (file)
index 0000000..b1a3df2
--- /dev/null
@@ -0,0 +1,121 @@
+/* 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;
+}
diff --git a/src/lib/cserve2/evas_cs2_utils.h b/src/lib/cserve2/evas_cs2_utils.h
new file mode 100644 (file)
index 0000000..fb37f35
--- /dev/null
@@ -0,0 +1,13 @@
+/* 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_ */
index ed6655b..313c23e 100644 (file)
@@ -37,17 +37,18 @@ EAPI void              evas_common_font_size_use             (RGBA_Font *fn);
 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);
index f6e4520..7636201 100644 (file)
@@ -97,7 +97,7 @@
 
 #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)
index 614e56e..c1308a9 100644 (file)
@@ -7,35 +7,6 @@
 
 #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
 {
@@ -75,12 +46,15 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, in
    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)
           {
@@ -102,11 +76,6 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, in
              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             
@@ -260,6 +229,7 @@ EAPI void
 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;
@@ -285,7 +255,6 @@ evas_common_font_draw_prepare(Evas_Text_Props *text_props)
    EVAS_FONT_WALK_TEXT_START()
      {
         Evas_Glyph glyph;
-        RGBA_Font_Glyph *fg;
         FT_UInt idx;
 
         if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
@@ -298,16 +267,16 @@ evas_common_font_draw_prepare(Evas_Text_Props *text_props)
         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;
 }
 
index 8e0bc15..4024565 100644 (file)
@@ -6,6 +6,10 @@
 #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>
@@ -76,7 +80,7 @@ _evas_common_font_int_free(RGBA_Font_Int *fi)
    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)
     {
@@ -85,6 +89,9 @@ _evas_common_font_int_free(RGBA_Font_Int *fi)
       fonts_use_usage -= fi->usage;
       fi->usage = 0;
     }
+#ifdef EVAS_CSERVE2
+   evas_cserve2_font_free(fi->cs2_handler);
+#endif
    free(fi);
 }
 
@@ -303,26 +310,43 @@ _evas_common_font_int_cache_init(RGBA_Font_Int *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;
 }
 
@@ -349,6 +373,11 @@ evas_common_font_int_load(const char *name, int size,
    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;
 }
@@ -469,24 +498,18 @@ 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)
+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);
@@ -523,13 +546,7 @@ evas_common_font_load(const char *name, int size, Font_Rend_Flags wanted_rend)
          {
             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;
               }
          }
@@ -538,13 +555,7 @@ evas_common_font_load(const char *name, int size, Font_Rend_Flags wanted_rend)
    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;
      }
 
@@ -585,13 +596,13 @@ evas_common_font_add(RGBA_Font *fn, const char *name, int size, Font_Rend_Flags
 }
 
 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);
@@ -608,6 +619,18 @@ evas_common_font_memory_add(RGBA_Font *fn, const char *name, int size, const voi
 }
 
 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;
@@ -617,14 +640,7 @@ evas_common_font_free(RGBA_Font *fn)
    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);
@@ -681,11 +697,11 @@ 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)
+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;
 }
@@ -709,9 +725,9 @@ evas_common_font_hinting_add(RGBA_Font *fn, const char *name, int size, Font_Hin
 }
 
 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;
@@ -729,36 +745,40 @@ _evas_common_font_int_clear(RGBA_Font_Int *fi)
         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;
index 0208b8b..bd4c678 100644 (file)
@@ -3,6 +3,10 @@
 
 #include "evas_font_private.h"
 
+#ifdef EVAS_CSERVE2
+# include "../../cserve2/evas_cs2_private.h"
+#endif
+
 #include <assert.h>
 
 #include FT_OUTLINE_H
@@ -218,7 +222,11 @@ evas_common_font_get_line_advance(RGBA_Font *fn)
         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;
@@ -360,9 +368,16 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt idx)
      {
         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;
 
@@ -404,10 +419,13 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt idx)
 
      {
         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;
@@ -416,6 +434,11 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt 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;
 }
@@ -426,6 +449,20 @@ evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *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)
@@ -439,7 +476,17 @@ evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg)
      }
    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. */
@@ -461,6 +508,40 @@ struct _Font_Char_Index
 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;
 
@@ -492,6 +573,50 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
 #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;
 }
 
index cd54a29..ddd6a5c 100644 (file)
@@ -331,7 +331,7 @@ evas_common_font_query_advance(RGBA_Font *fn, const Evas_Text_Props *text_props,
    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;
index b2e291e..c1c1a23 100644 (file)
@@ -47,6 +47,8 @@ evas_common_text_props_content_ref(Evas_Text_Props *props)
       return;
 
    props->info->refcount++;
+   if (props->font_instance) 
+     ((RGBA_Font_Int *)props->font_instance)->references++;
 }
 
 void
@@ -56,6 +58,12 @@ evas_common_text_props_content_unref(Evas_Text_Props *props)
    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)
@@ -317,6 +325,7 @@ _content_create_ot(RGBA_Font_Int *fi, const Eina_Unicode *text,
         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 =
@@ -435,6 +444,7 @@ _content_create_regular(RGBA_Font_Int *fi, const Eina_Unicode *text,
 
         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;
 
@@ -476,8 +486,14 @@ evas_common_text_props_content_create(void *_fi, const Eina_Unicode *text,
      }
    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)
      {
index e30827d..a10ce7d 100644 (file)
@@ -50,12 +50,10 @@ struct _Evas_Font_Glyph_Info
 {
    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;
 };
index 063c479..18a5e95 100644 (file)
@@ -89,7 +89,6 @@ EVAS_EINA_STATIC_MODULE_DEFINE(engine, gl_x11);
 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);
@@ -148,9 +147,6 @@ static const struct {
 #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
@@ -160,18 +156,18 @@ static const struct {
 #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
index 3ace2b6..c9a9511 100644 (file)
@@ -400,6 +400,7 @@ typedef struct _RGBA_Font             RGBA_Font;
 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;
@@ -957,6 +958,9 @@ struct _RGBA_Font_Int
                                      in order to comply with the wanted_rend. */
 
    Eina_List       *task;
+#ifdef EVAS_CSERVE2
+   void            *cs2_handler;
+#endif
 
    int              generation;
 
@@ -978,13 +982,32 @@ struct _RGBA_Font_Source
    } 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);
index 9d3fa90..d21ab0a 100644 (file)
@@ -803,9 +803,9 @@ struct _Evas_Func
    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);
index e29fb98..3ee22df 100644 (file)
@@ -44,9 +44,6 @@ endif
 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
index 681bdc5..852a603 100644 (file)
@@ -44,6 +44,7 @@ eng_window_new(Display *disp,
 #endif
    XVisualInfo *vi_use;
    const GLubyte *vendor, *renderer, *version;
+   int blacklist = 0;
 
    if (!_evas_gl_x11_vi) return NULL;
 
@@ -227,6 +228,23 @@ eng_window_new(Display *disp,
         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)
@@ -284,7 +302,6 @@ eng_window_new(Display *disp,
      {
         int i, j,  num;
         GLXFBConfig *fbc;
-        int blacklist = 0;
 
         if (gw->glxwin)
           {
diff --git a/src/modules/engines/software_16_ddraw/Evas_Engine_Software_16_DDraw.h b/src/modules/engines/software_16_ddraw/Evas_Engine_Software_16_DDraw.h
deleted file mode 100644 (file)
index 3c1547a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#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__ */
diff --git a/src/modules/engines/software_16_ddraw/Makefile.am b/src/modules/engines/software_16_ddraw/Makefile.am
deleted file mode 100644 (file)
index f68f24d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-
-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
diff --git a/src/modules/engines/software_16_ddraw/evas_ddraw_buffer.cpp b/src/modules/engines/software_16_ddraw/evas_ddraw_buffer.cpp
deleted file mode 100644 (file)
index 7a0a8b7..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#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);
-}
diff --git a/src/modules/engines/software_16_ddraw/evas_ddraw_main.cpp b/src/modules/engines/software_16_ddraw/evas_ddraw_main.cpp
deleted file mode 100644 (file)
index 7a2eb7f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#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
-}
diff --git a/src/modules/engines/software_16_ddraw/evas_engine.c b/src/modules/engines/software_16_ddraw/evas_engine.c
deleted file mode 100644 (file)
index 9629781..0000000
+++ /dev/null
@@ -1,628 +0,0 @@
-#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
diff --git a/src/modules/engines/software_16_ddraw/evas_engine.h b/src/modules/engines/software_16_ddraw/evas_engine.h
deleted file mode 100644 (file)
index fe85e97..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#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__ */
index 536d507..d4f0230 100644 (file)
@@ -1148,10 +1148,10 @@ eng_font_load(void *data __UNUSED__, const char *name, int size,
 }
 
 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 *
@@ -1162,10 +1162,10 @@ eng_font_add(void *data __UNUSED__, Evas_Font_Set *font, const char *name, int s
 }
 
 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
index 48c0f99..a61f711 100644 (file)
@@ -667,7 +667,7 @@ eng_setup(Evas *e, void *in)
                   /* 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)
                          {
index d7d372f..aa1e3d0 100644 (file)
@@ -1482,6 +1482,24 @@ START_TEST(evas_textblock_editing)
    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;