evas/cserve2: Add font and glyphs loading implementation

to cserve2.
Big commit that implements the entire functionality. Besides loading
fonts and glyphs, and sharing the glyph bitmaps with clients, it also
adds:
- new request system, with a much better abstraction;
- new working slaves management;
- slaves can be threads or process now;
- started a debugging and statistics implementation on server.

The image caching part still uses the old request and slaves system, but
should be changed to use the new one soon and get more easily
maintainable.



SVN revision: 72699
This commit is contained in:
Rafael Antognolli 2012-06-22 20:31:17 +00:00
parent de28f1ed31
commit 64fecc2fab
12 changed files with 1953 additions and 148 deletions

View File

@ -45,7 +45,7 @@ if EVAS_CSERVE2
SUBDIRS = loaders SUBDIRS = loaders
libexec_PROGRAMS = evas_cserve2 evas_cserve2_slave dummy_slave libexec_PROGRAMS = evas_cserve2 evas_cserve2_slave dummy_slave
bin_PROGRAMS = evas_cserve2_client bin_PROGRAMS = evas_cserve2_client evas_cserve2_usage
AM_CPPFLAGS = \ AM_CPPFLAGS = \
-I. \ -I. \
@ -56,7 +56,8 @@ AM_CPPFLAGS = \
-DPACKAGE_LIB_DIR=\"$(libdir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \
-DPACKAGE_LIBEXEC_DIR=\"$(libexecdir)\" \ -DPACKAGE_LIBEXEC_DIR=\"$(libexecdir)\" \
@FREETYPE_CFLAGS@ \ @FREETYPE_CFLAGS@ \
@EINA_CFLAGS@ @EINA_CFLAGS@ \
@EET_CFLAGS@
evas_cserve2_SOURCES = \ evas_cserve2_SOURCES = \
evas_cserve2.h \ evas_cserve2.h \
@ -70,14 +71,24 @@ evas_cserve2_requests.c \
evas_cserve2_fonts.c \ evas_cserve2_fonts.c \
evas_cserve2_main_loop_linux.c evas_cserve2_main_loop_linux.c
libevas_cserve2_utils_la = $(top_builddir)/src/lib/cserve2/libevas_cserve2_utils.la
evas_cserve2_LDADD = \ evas_cserve2_LDADD = \
@FREETYPE_LIBS@ \ @FREETYPE_LIBS@ \
@EINA_LIBS@ \ @EINA_LIBS@ \
@EFL_SHM_OPEN_LIBS@ @EFL_SHM_OPEN_LIBS@ \
@EET_LIBS@ \
$(libevas_cserve2_utils_la)
evas_cserve2_client_SOURCES = \ evas_cserve2_client_SOURCES = \
evas_cserve2_client.c evas_cserve2_client.c
evas_cserve2_usage_SOURCES = \
evas_cserve2_usage.c
evas_cserve2_usage_LDADD = \
@EINA_LIBS@
evas_cserve2_slave_SOURCES = \ evas_cserve2_slave_SOURCES = \
evas_cserve2_slave.c \ evas_cserve2_slave.c \
evas_cserve2_utils.c evas_cserve2_utils.c

View File

@ -89,8 +89,8 @@ error_send(int fd, Error_Type err)
return response_send(fd, ERROR, &err, sizeof(Error_Type)); return response_send(fd, ERROR, &err, sizeof(Error_Type));
} }
void * static void *
cserve2_shm_map(const char *name, size_t length, off_t offset) _cserve2_shm_map(const char *name, size_t length, off_t offset)
{ {
void *map; void *map;
int fd; int fd;
@ -106,11 +106,13 @@ cserve2_shm_map(const char *name, size_t length, off_t offset)
return map; return map;
} }
void /*
cserve2_shm_unmap(void *map, size_t length) static void
_cserve2_shm_unmap(void *map, size_t length)
{ {
munmap(map, length); munmap(map, length);
} }
*/
static Error_Type static Error_Type
image_open(const char *file __UNUSED__, const char *key __UNUSED__, Slave_Msg_Image_Opened *result) 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 static Error_Type
image_load(const char *shmfile, Slave_Msg_Image_Load *params) image_load(const char *shmfile, Slave_Msg_Image_Load *params)
{ {
char *map = cserve2_shm_map(shmfile, params->shm.mmap_size, char *map = _cserve2_shm_map(shmfile, params->shm.mmap_size,
params->shm.mmap_offset); params->shm.mmap_offset);
if (map == MAP_FAILED) if (map == MAP_FAILED)
return CSERVE2_RESOURCE_ALLOCATION_FAILED; return CSERVE2_RESOURCE_ALLOCATION_FAILED;

View File

@ -21,6 +21,8 @@
#endif #endif
#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_bin_log_dom, __VA_ARGS__) #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; extern int _evas_cserve2_bin_log_dom;
typedef struct _Slave Slave; typedef struct _Slave Slave;
@ -119,11 +121,12 @@ struct _Slave_Msg_Font_Load {
void *ftdata1; // Freetype file source info comes here void *ftdata1; // Freetype file source info comes here
void *ftdata2; // Freetype font info comes here void *ftdata2; // Freetype font info comes here
unsigned int rend_flags; unsigned int rend_flags;
unsigned int hint;
unsigned int size; unsigned int size;
unsigned int dpi; unsigned int dpi;
const char *name; const char *name;
const char *file; const char *file;
void *data;
int datasize;
}; };
struct _Slave_Msg_Font_Loaded { struct _Slave_Msg_Font_Loaded {
@ -131,11 +134,58 @@ struct _Slave_Msg_Font_Loaded {
void *ftdata2; 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_Load Slave_Msg_Font_Load;
typedef struct _Slave_Msg_Font_Loaded Slave_Msg_Font_Loaded; 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_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_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); typedef void (*Font_Request_Error)(Client *c, void *data, Error_Type error, unsigned int rid);
@ -161,6 +211,8 @@ typedef enum {
CSERVE2_REQ_LAST CSERVE2_REQ_LAST
} Font_Request_Type; } Font_Request_Type;
typedef struct _Glyph_Entry Glyph_Entry;
typedef void (*Fd_Watch_Cb)(int fd, Fd_Flags flags, void *data); typedef void (*Fd_Watch_Cb)(int fd, Fd_Flags flags, void *data);
typedef void (*Timeout_Cb)(void); /* void* for compat? */ typedef void (*Timeout_Cb)(void); /* void* for compat? */
typedef void (*Main_Loop_Child_Dead_Cb)(int pid, int status); /* 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); 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_map_size_get(const Shm_Handle *shm);
size_t cserve2_shm_size_get(const Shm_Handle *shm); size_t cserve2_shm_size_get(const Shm_Handle *shm);
void *cserve2_shm_map(Shm_Handle *shm);
void cserve2_shm_unmap(Shm_Handle *shm);
size_t cserve2_shm_size_normalize(size_t size);
void cserve2_command_run(Client *client, Message_Type type); void cserve2_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_preload(Client *client, unsigned int client_image_id, unsigned int rid);
void cserve2_cache_image_unload(Client *client, unsigned int client_image_id); void cserve2_cache_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); 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(Font_Request *req, Client *client, Error_Type err);
void cserve2_request_cancel_all(Font_Request *req, Error_Type err); void cserve2_request_cancel_all(Font_Request *req, Error_Type err);
void cserve2_requests_init(void); 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_init(void);
void cserve2_font_shutdown(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_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 */ #endif /* _EVAS_CSERVE2_H */

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@
#include "evas_cserve2.h" #include "evas_cserve2.h"
static const char *SOCK_PATH = "/tmp/cserve2.socket";
static unsigned int _rid_count = 0; static unsigned int _rid_count = 0;
static struct sockaddr_un socket_local; static struct sockaddr_un socket_local;

View File

@ -2,23 +2,49 @@
# include "config.h" # include "config.h"
#endif #endif
#ifdef BUILD_FONT_LOADER_EET
#include <Eet.h>
#endif
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_GLYPH_H #include FT_GLYPH_H
#include FT_SIZES_H #include FT_SIZES_H
#include FT_TYPES_H
#include FT_MODULE_H #include FT_MODULE_H
#include FT_OUTLINE_H
#include "evas_cserve2.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 FT_Library cserve2_ft_lib = 0;
static int initialised = 0; static int initialised = 0;
typedef struct _Font_Info Font_Info;
typedef struct _Font_Source_Info Font_Source_Info;
struct _Font_Info struct _Font_Info
{ {
Font_Source_Info *fsi;
FT_Size size; 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; int max_h;
unsigned int runtime_rend; unsigned int runtime_rend;
int shmsize;
}; };
struct _Font_Source_Info struct _Font_Source_Info
@ -26,11 +52,11 @@ struct _Font_Source_Info
FT_Face face; FT_Face face;
int orig_upem; int orig_upem;
int current_size; 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 * static void *
_font_slave_error_send(Error_Type error) _font_slave_error_send(Error_Type error)
{ {
@ -40,29 +66,80 @@ _font_slave_error_send(Error_Type error)
return e; 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 * static Font_Source_Info *
_font_slave_source_load(const char *file) _font_slave_source_load(const char *file, const char *name)
{ {
int error; 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 (!name)
if (error)
{ {
free(fsi); error = FT_New_Face(cserve2_ft_lib, file, 0, &(fsi->face));
return NULL; 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); error = FT_Select_Charmap(fsi->face, ft_encoding_unicode);
if (error) if (error)
{ {
FT_Done_Face(fsi->face); FT_Done_Face(fsi->face);
free(fsi->data);
free(fsi); free(fsi);
return NULL; return NULL;
} }
fsi->orig_upem = fsi->face->units_per_EM; fsi->orig_upem = fsi->face->units_per_EM;
fsi->current_size = 0; fsi->current_size = 0;
fsi->current_dpi = 0;
return fsi; return fsi;
} }
@ -79,46 +156,55 @@ _font_slave_int_load(const Slave_Msg_Font_Load *msg, Font_Source_Info *fsi)
if (!error) if (!error)
FT_Activate_Size(fi->size); FT_Activate_Size(fi->size);
fi->fsize = msg->size;
fi->dpi = msg->dpi;
fi->real_size = msg->size * 64; fi->real_size = msg->size * 64;
fi->fsi = fsi;
error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, msg->dpi, msg->dpi); error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, msg->dpi, msg->dpi);
if (error) if (error)
{ error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size);
fi->real_size = msg->size;
error = FT_Set_Pixel_Sizes(fsi->face, 0, fi->real_size);
}
if (error) if (error)
{ {
int i; int i, maxd = 0x7fffffff;
int chosen_size = 0; int chosen_size = 0;
int chosen_width = 0; int chosen_size2 = 0;
for (i = 0; i < fsi->face->num_fixed_sizes; i++) for (i = 0; i < fsi->face->num_fixed_sizes; i++)
{ {
int s; int s, cd;
int d, cd;
s = fsi->face->available_sizes[i].height; s = fsi->face->available_sizes[i].size;
cd = chosen_size - msg->size; cd = chosen_size - fi->real_size;
if (cd < 0) cd = -cd; if (cd < 0) cd = -cd;
d = s - msg->size; if (cd < maxd)
if (d < 0) d = -d;
if (d < cd)
{ {
chosen_width = fsi->face->available_sizes[i].width; maxd = cd;
chosen_size = s; 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; 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) if (error)
{ {
ERR("Could not choose the font size for font: '%s'.", msg->name); error = FT_Set_Char_Size(fsi->face, 0, fi->real_size, fi->dpi, fi->dpi);
FT_Done_Size(fi->size); if (error)
free(fi); {
return NULL; /* 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_Source_Info *fsi;
Font_Info *fi; Font_Info *fi;
DBG("slave received FONT_LOAD: '%s'", msg->name);
fsi = msg->ftdata1; fsi = msg->ftdata1;
/* Loading Font Source */ /* Loading Font Source */
if (!fsi) if (!fsi)
fsi = _font_slave_source_load(msg->file); fsi = _font_slave_source_load(msg->file, msg->name);
// FIXME: Return correct error message // FIXME: Return correct error message
if (!fsi) if (!fsi)
@ -175,8 +262,8 @@ _font_slave_load(const void *cmddata, void *data __UNUSED__)
fi = _font_slave_int_load(msg, fsi); fi = _font_slave_int_load(msg, fsi);
if (!fi) if (!fi)
{ {
FT_Done_Face(fsi->face); if (!msg->ftdata1)
free(fsi); cserve2_font_source_ft_free(fsi);
return NULL; return NULL;
} }
@ -187,6 +274,241 @@ _font_slave_load(const void *cmddata, void *data __UNUSED__)
return response; 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 index, 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, index,
FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP |
hintflags[hint]);
if (error)
{
ERR("Could not load glyph %d", index);
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 index)
{
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 = index;
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 * void *
cserve2_font_slave_cb(Slave_Thread_Data *sd __UNUSED__, Slave_Command *cmd, const void *cmddata, void *data) 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); response = _font_slave_load(cmddata, data);
break; break;
case FONT_GLYPHS_LOAD: case FONT_GLYPHS_LOAD:
// command for FONT_GLYPHS_LOAD response = _font_slave_glyphs_load(cmddata, data);
break; break;
default: default:
ERR("Invalid command for font slave: %d", *cmd); ERR("Invalid command for font slave: %d", *cmd);
@ -224,6 +546,10 @@ cserve2_font_init(void)
error = FT_Init_FreeType(&cserve2_ft_lib); error = FT_Init_FreeType(&cserve2_ft_lib);
if (error) return; if (error) return;
#ifdef BUILD_FONT_LOADER_EET
eet_init();
#endif
} }
void void
@ -239,4 +565,27 @@ cserve2_font_shutdown(void)
FT_Done_FreeType(cserve2_ft_lib); FT_Done_FreeType(cserve2_ft_lib);
cserve2_ft_lib = 0; 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);
} }

View File

@ -33,13 +33,6 @@ static Eina_Hash *client_list = NULL;
static Eina_Inlist *slaves_idle = NULL; static Eina_Inlist *slaves_idle = NULL;
static Eina_Inlist *slaves_working = NULL; static Eina_Inlist *slaves_working = NULL;
struct _Glyph_Request {
unsigned int index;
unsigned int offset;
};
typedef struct _Glyph_Request Glyph_Request;
void void
cserve2_client_error_send(Client *client, unsigned int rid, int error_code) cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
{ {
@ -270,52 +263,83 @@ static void
_cserve2_client_font_load(Client *client) _cserve2_client_font_load(Client *client)
{ {
Msg_Font_Load *msg = (Msg_Font_Load *)client->msg.buf; 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", INF("Received %s command: RID=%d",
(msg->base.type == CSERVE2_FONT_LOAD) ? "FONT_LOAD" : "FONT_UNLOAD", (msg->base.type == CSERVE2_FONT_LOAD) ? "FONT_LOAD" : "FONT_UNLOAD",
msg->base.rid); msg->base.rid);
INF("Font: %s, rend_flags: %d, hint: %d, size: %d, dpi: %d", INF("Font: %s, rend_flags: %d, size: %d, dpi: %d",
name, msg->rend_flags, msg->hint, msg->size, msg->dpi); name, msg->rend_flags, msg->size, msg->dpi);
cserve2_cache_font_load(client, name, msg->pathlen, msg->rend_flags, if (msg->base.type == CSERVE2_FONT_LOAD)
msg->hint, msg->size, msg->dpi, msg->base.rid); 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 static void
_cserve2_client_font_glyphs_request(Client *client) _cserve2_client_font_glyphs_request(Client *client)
{ {
Msg_Font_Glyphs_Request *msg = (Msg_Font_Glyphs_Request *)client->msg.buf; Msg_Font_Glyphs_Request *msg = (Msg_Font_Glyphs_Request *)client->msg.buf;
char fontpath[PATH_MAX]; char source[PATH_MAX], fontpath[PATH_MAX], *buf;
Glyph_Request *glyphs; unsigned int *glyphs;
unsigned int i;
const char *bufpos = client->msg.buf;
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); glyphs = malloc(sizeof(*glyphs) * msg->nglyphs);
memcpy(glyphs, buf, sizeof(*glyphs) * msg->nglyphs);
for (i = 0; i < msg->nglyphs; i++)
{
memcpy(&glyphs[i], bufpos, sizeof(*glyphs));
bufpos += sizeof(*glyphs);
}
if (msg->base.type == CSERVE2_FONT_GLYPHS_LOAD) if (msg->base.type == CSERVE2_FONT_GLYPHS_LOAD)
{ {
INF("Received CSERVE2_FONT_GLYPHS_LOAD command: RID=%d", INF("Received CSERVE2_FONT_GLYPHS_LOAD command: RID=%d",
msg->base.rid); 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 else
{ {
INF("Received CSERVE2_FONT_GLYPHS_USED command: RID=%d", INF("Received CSERVE2_FONT_GLYPHS_USED command: RID=%d",
msg->base.rid); 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 void
cserve2_command_run(Client *client, Message_Type type) cserve2_command_run(Client *client, Message_Type type)
{ {
@ -347,6 +371,12 @@ cserve2_command_run(Client *client, Message_Type type)
case CSERVE2_FONT_GLYPHS_USED: case CSERVE2_FONT_GLYPHS_USED:
_cserve2_client_font_glyphs_request(client); _cserve2_client_font_glyphs_request(client);
break; break;
case CSERVE2_STATS:
_cserve2_client_stats_request(client);
break;
case CSERVE2_FONT_DEBUG:
_cserve2_client_font_debug_request(client);
break;
default: default:
WRN("Unhandled message"); WRN("Unhandled message");
} }

View File

@ -81,7 +81,7 @@ typedef struct _Waiter Waiter;
struct _Request_Queue struct _Request_Queue
{ {
Eina_Inlist *waiting; 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; typedef struct _Request_Queue Request_Queue;
@ -89,6 +89,8 @@ typedef struct _Request_Queue Request_Queue;
static Request_Queue *requests = NULL; static Request_Queue *requests = NULL;
// static Eina_List *processing = NULL; // static Eina_List *processing = NULL;
static void _cserve2_requests_process(void);
static void static void
_request_waiter_add(Font_Request *req, Client *client, unsigned int rid) _request_waiter_add(Font_Request *req, Client *client, unsigned int rid)
{ {
@ -109,15 +111,17 @@ cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Fo
req = NULL; req = NULL;
/* Check if this request was already being processed. */
EINA_INLIST_FOREACH(requests[type].processing, r) EINA_INLIST_FOREACH(requests[type].processing, r)
{ {
if (r->data == data) if (r->data != data)
continue; continue;
req = r; req = r;
break; break;
} }
/* Check if this request was already waiting to be processed. */
if (!req) if (!req)
{ {
EINA_INLIST_FOREACH(requests[type].waiting, r) EINA_INLIST_FOREACH(requests[type].waiting, r)
@ -130,22 +134,33 @@ cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Fo
} }
} }
/* create new request */
if (!req) if (!req)
{ {
DBG("Add request for rid: %d", rid); DBG("Add request for rid: %d", rid);
req = malloc(sizeof(*req)); req = malloc(sizeof(*req));
req->type = type;
req->data = data; req->data = data;
req->waiters = NULL; req->waiters = NULL;
req->processing = EINA_FALSE; req->processing = EINA_FALSE;
req->funcs = funcs;
requests[type].waiting = eina_inlist_append(requests[type].waiting, requests[type].waiting = eina_inlist_append(requests[type].waiting,
EINA_INLIST_GET(req)); EINA_INLIST_GET(req));
} }
_request_waiter_add(req, client, rid); _request_waiter_add(req, client, rid);
_cserve2_requests_process();
return req; return req;
} }
void
cserve2_request_waiter_add(Font_Request *req, unsigned int rid, Client *client)
{
_request_waiter_add(req, client, rid);
}
void void
cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err) cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err)
{ {
@ -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, // TODO: When we have speculative preload, there may be no waiters,
// so we need a flag or something else to make things still load. // 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; Eina_Inlist **reqlist = &requests[req->type].waiting;
*reqlist = eina_inlist_remove(*reqlist, EINA_INLIST_GET(req)); *reqlist = eina_inlist_remove(*reqlist, EINA_INLIST_GET(req));
// TODO: If the request is being processed, it can't be deleted. Must // TODO: If the request is being processed, it can't be deleted. Must
// be marked as delete_me instead. // be marked as delete_me instead.
req->funcs->msg_free(req->msg); req->funcs->msg_free(req->msg, req->data);
free(req); free(req);
} }
@ -195,9 +210,12 @@ cserve2_request_cancel_all(Font_Request *req, Error_Type err)
free(w); free(w);
} }
if (req->processing)
return;
requests[req->type].waiting = eina_inlist_remove( requests[req->type].waiting = eina_inlist_remove(
requests[req->type].waiting, EINA_INLIST_GET(req)); requests[req->type].waiting, EINA_INLIST_GET(req));
req->funcs->msg_free(req->msg); req->funcs->msg_free(req->msg, req->data);
free(req); free(req);
} }
@ -226,7 +244,7 @@ _cserve2_request_failed(Font_Request *req, Error_Type type)
free(w); 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_remove(
requests[req->type].processing, EINA_INLIST_GET(req)); requests[req->type].processing, EINA_INLIST_GET(req));
free(req); free(req);
@ -252,7 +270,7 @@ _slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
free(w); 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 // FIXME: We shouldn't free this message directly, it must be freed by a
// callback. // callback.
free(msg); free(msg);
@ -265,6 +283,8 @@ _slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
idle = &_workers[sw->type].idle; idle = &_workers[sw->type].idle;
*working = eina_list_remove(*working, sw); *working = eina_list_remove(*working, sw);
*idle = eina_list_append(*idle, sw); *idle = eina_list_append(*idle, sw);
_cserve2_requests_process();
} }
static void static void
@ -338,6 +358,8 @@ _cserve2_request_dispatch(Slave_Worker *sw, Slave_Command ctype, Font_Request *r
int size; int size;
char *slave_msg = req->funcs->msg_create(req->data, &size); char *slave_msg = req->funcs->msg_create(req->data, &size);
DBG("dispatching message of type %d to slave.", req->type);
if (!slave_msg) if (!slave_msg)
{ {
ERR("Could not create slave message for request type %d.", req->type); ERR("Could not create slave message for request type %d.", req->type);
@ -352,8 +374,8 @@ _cserve2_request_dispatch(Slave_Worker *sw, Slave_Command ctype, Font_Request *r
return EINA_TRUE; return EINA_TRUE;
} }
void static void
cserve2_requests_process(void) _cserve2_requests_process(void)
{ {
int rtype, j; int rtype, j;
@ -366,7 +388,7 @@ cserve2_requests_process(void)
for (j = 0; _request_match[j].rtype != CSERVE2_REQ_LAST; j++) for (j = 0; _request_match[j].rtype != CSERVE2_REQ_LAST; j++)
{ {
if (_request_match[j].rtype == (unsigned int)j) if (_request_match[j].rtype == rtype)
{ {
type = _request_match[j].stype; type = _request_match[j].stype;
ctype = _request_match[j].ctype; ctype = _request_match[j].ctype;
@ -387,7 +409,7 @@ cserve2_requests_process(void)
idle = &_workers[type].idle; idle = &_workers[type].idle;
working = &_workers[type].working; working = &_workers[type].working;
while (requests[j].waiting && while (requests[rtype].waiting &&
(eina_list_count(*working) < max_workers)) (eina_list_count(*working) < max_workers))
{ {
Slave_Worker *sw; Slave_Worker *sw;

View File

@ -27,10 +27,30 @@ struct _Shm_Handle
off_t image_offset; off_t image_offset;
size_t map_size; size_t map_size;
size_t image_size; size_t image_size;
int refcount;
void *data;
}; };
static int id = 0; 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 * Shm_Handle *
cserve2_shm_request(size_t size) cserve2_shm_request(size_t size)
{ {
@ -38,7 +58,6 @@ cserve2_shm_request(size_t size)
Shm_Handle *shm; Shm_Handle *shm;
char shmname[NAME_MAX]; char shmname[NAME_MAX];
size_t map_size; size_t map_size;
long pagesize;
int fd; int fd;
map = calloc(1, sizeof(Shm_Mapping)); map = calloc(1, sizeof(Shm_Mapping));
@ -59,14 +78,7 @@ cserve2_shm_request(size_t size)
} }
} while (fd == -1); } while (fd == -1);
pagesize = sysconf(_SC_PAGESIZE); map_size = cserve2_shm_size_normalize(size);
if (pagesize < 1)
{
ERR("sysconf() reported weird value for PAGESIZE, assuming 4096.");
pagesize = 4096;
}
map_size = ((size + pagesize - 1) / pagesize) * pagesize;
if (ftruncate(fd, map_size) == -1) if (ftruncate(fd, map_size) == -1)
{ {
@ -106,6 +118,9 @@ cserve2_shm_unref(Shm_Handle *shm)
Shm_Mapping *map = shm->mapping; Shm_Mapping *map = shm->mapping;
map->segments = eina_inlist_remove(map->segments, EINA_INLIST_GET(shm)); map->segments = eina_inlist_remove(map->segments, EINA_INLIST_GET(shm));
if (shm->data)
munmap(shm->data, shm->image_size);
free(shm); free(shm);
if (map->segments) if (map->segments)
@ -145,3 +160,36 @@ cserve2_shm_size_get(const Shm_Handle *shm)
{ {
return shm->image_size; 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;
}

View File

@ -187,8 +187,8 @@ error_send(int fd, Error_Type err)
return response_send(fd, ERROR, &err, sizeof(Error_Type)); return response_send(fd, ERROR, &err, sizeof(Error_Type));
} }
void * static void *
cserve2_shm_map(const char *name, size_t length, off_t offset) _cserve2_shm_map(const char *name, size_t length, off_t offset)
{ {
void *map; void *map;
int fd; int fd;
@ -204,8 +204,8 @@ cserve2_shm_map(const char *name, size_t length, off_t offset)
return map; return map;
} }
void static void
cserve2_shm_unmap(void *map, size_t length) _cserve2_shm_unmap(void *map, size_t length)
{ {
munmap(map, 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; Evas_Loader_Module_Api *api;
int err; int err;
Error_Type ret = CSERVE2_NONE; Error_Type ret = CSERVE2_NONE;
char *map = cserve2_shm_map(shmfile, params->shm.mmap_size, char *map = _cserve2_shm_map(shmfile, params->shm.mmap_size,
params->shm.mmap_offset); params->shm.mmap_offset);
if (map == MAP_FAILED) if (map == MAP_FAILED)
return CSERVE2_RESOURCE_ALLOCATION_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; result->alpha_sparse = ilp.alpha_sparse;
done: done:
cserve2_shm_unmap(map, params->shm.mmap_size); _cserve2_shm_unmap(map, params->shm.mmap_size);
return ret; return ret;
} }

View File

@ -0,0 +1,230 @@
#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("Font Usage Statistics:\n");
printf("Requested usage: %d bytes\n", msg->fonts.requested_usage);
printf("Real usage: %d bytes\n", msg->fonts.real_usage);
printf("Fonts load time: %dus\n", msg->fonts.fonts_load);
printf("Fonts used load time: %dus\n", msg->fonts.fonts_used_load);
printf("Glyphs load time: %dus\n", msg->fonts.glyphs_load);
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();
}

View File

@ -22,6 +22,8 @@ typedef enum {
CSERVE2_FONT_GLYPHS_LOAD, CSERVE2_FONT_GLYPHS_LOAD,
CSERVE2_FONT_GLYPHS_LOADED, CSERVE2_FONT_GLYPHS_LOADED,
CSERVE2_FONT_GLYPHS_USED, CSERVE2_FONT_GLYPHS_USED,
CSERVE2_STATS,
CSERVE2_FONT_DEBUG,
CSERVE2_ERROR CSERVE2_ERROR
} Message_Type; } Message_Type;
@ -127,9 +129,9 @@ struct _Msg_Close {
*/ */
struct _Msg_Font_Load { struct _Msg_Font_Load {
Msg_Base base; Msg_Base base;
unsigned int sourcelen; // font id
unsigned int pathlen; // font id unsigned int pathlen; // font id
unsigned int rend_flags; // font id unsigned int rend_flags; // font id
unsigned int hint; // font id
unsigned int size; // font id unsigned int size; // font id
unsigned int dpi; // font id unsigned int dpi; // font id
}; };
@ -146,18 +148,19 @@ struct _Msg_Font_Loaded {
/** /**
* @struct _Msg_Font_Glyphs_Request * @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 path strings follow the struct inside the message, as well as
* the list of glyphs to be loaded. * the list of glyphs to be loaded.
*/ */
struct _Msg_Font_Glyphs_Request { struct _Msg_Font_Glyphs_Request {
Msg_Base base; Msg_Base base;
unsigned int sourcelen; // font id
unsigned int pathlen; // font id unsigned int pathlen; // font id
unsigned int rend_flags; // font id unsigned int rend_flags; // font id
unsigned int hint; // font id
unsigned int size; // font id unsigned int size; // font id
unsigned int dpi; // font id unsigned int dpi; // font id
unsigned int hint;
unsigned int nglyphs; unsigned int nglyphs;
}; };
@ -180,6 +183,12 @@ struct _Msg_Font_Glyphs_Request {
* - struct { * - struct {
* unsigned int index; * unsigned int index;
* unsigned int offset; * unsigned int offset;
* unsigned int size;
* unsigned int rows;
* unsigned int width;
* unsigned int pitch;
* unsigned int num_grays;
* unsigned int pixel_mode;
* } glarray[]; * } glarray[];
*/ */
struct _Msg_Font_Glyphs_Loaded { struct _Msg_Font_Glyphs_Loaded {
@ -187,6 +196,56 @@ struct _Msg_Font_Glyphs_Loaded {
unsigned int ncaches; unsigned int ncaches;
}; };
struct _Msg_Stats {
Msg_Base base;
struct {
unsigned int requested_usage;
unsigned int real_usage;
int fonts_load; // total time spent loading fonts
int fonts_used_load; // total time spent loading fonts that are
// really used
int glyphs_load; // total time spent loading glyphs
} fonts;
};
/*
* @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 { struct _Msg_Error {
Msg_Base base; Msg_Base base;
int error; int error;
@ -206,6 +265,8 @@ typedef struct _Msg_Font_Load Msg_Font_Load;
typedef struct _Msg_Font_Loaded Msg_Font_Loaded; typedef struct _Msg_Font_Loaded Msg_Font_Loaded;
typedef struct _Msg_Font_Glyphs_Request Msg_Font_Glyphs_Request; typedef struct _Msg_Font_Glyphs_Request Msg_Font_Glyphs_Request;
typedef struct _Msg_Font_Glyphs_Loaded Msg_Font_Glyphs_Loaded; 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; typedef struct _Msg_Error Msg_Error;
#endif #endif