4 #include <sys/socket.h>
14 #include "evas_cs2_private.h"
15 #include "evas_cs2_utils.h"
19 typedef void (*Op_Callback)(void *data, const void *msg);
25 struct _Client_Request {
32 typedef struct _File_Entry File_Entry;
33 typedef struct _Client_Request Client_Request;
35 static int cserve2_init = 0;
36 static int socketfd = -1;
38 static unsigned int _rid_count = 0;
39 static unsigned int _file_id = 0;
40 static unsigned int _data_id = 0;
42 static Eina_List *_requests = NULL;
44 static struct sockaddr_un socksize;
46 #define UNIX_PATH_MAX sizeof(socksize.sun_path)
50 _socket_path_set(char *path)
53 char buf[UNIX_PATH_MAX];
55 env = getenv("EVAS_CSERVE2_SOCKET");
58 strncpy(path, env, UNIX_PATH_MAX - 1);
62 snprintf(buf, sizeof(buf), "/tmp/.evas-cserve2-%x.socket", (int)getuid());
63 /* FIXME: check we can actually create this socket */
66 env = getenv("XDG_RUNTIME_DIR");
72 env = getenv("TMPDIR");
78 snprintf(buf, sizeof(buf), "%s/evas-cserve2-%x.socket", env, getuid());
79 /* FIXME: check we can actually create this socket */
88 struct sockaddr_un remote;
90 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
96 remote.sun_family = AF_UNIX;
97 _socket_path_set(remote.sun_path);
98 len = strlen(remote.sun_path) + sizeof(remote.sun_family);
99 if (connect(s, (struct sockaddr *)&remote, len) == -1)
105 fcntl(s, F_SETFL, O_NONBLOCK);
109 DBG("connected to cserve2 server.");
114 _server_disconnect(void)
121 _request_answer_add(Message_Type type, unsigned int rid, Op_Callback cb, void *data)
123 Client_Request *cr = calloc(1, sizeof(*cr));
130 _requests = eina_list_append(_requests, cr);
134 _server_safe_send(int fd, const void *data, int size)
138 const char *msg = data;
142 ret = send(fd, msg + sent, size - sent, MSG_NOSIGNAL);
145 if ((errno == EAGAIN) || (errno == EINTR))
156 _server_send(const void *buf, int size, Op_Callback cb, void *data)
159 if (!_server_safe_send(socketfd, &size, sizeof(size)))
161 ERR("Couldn't send message size to server.");
164 if (!_server_safe_send(socketfd, buf, size))
166 ERR("Couldn't send message body to server.");
174 case CSERVE2_SETOPTS:
176 case CSERVE2_PRELOAD:
177 case CSERVE2_FONT_LOAD:
178 case CSERVE2_FONT_GLYPHS_LOAD:
179 _request_answer_add(msg->type, msg->rid, cb, data);
188 static int sr_size = 0;
189 static int sr_got = 0;
190 static char *sr_buf = NULL;
193 _server_read(int *size)
201 n = recv(socketfd, &sr_size, sizeof(sr_size), 0);
205 sr_buf = malloc(sr_size);
208 n = recv(socketfd, sr_buf + sr_got, sr_size - sr_got, 0);
213 if (sr_got < sr_size)
226 evas_cserve2_init(void)
231 DBG("Connecting to cserve2.");
232 if (!_server_connect())
242 evas_cserve2_shutdown(void)
244 if ((--cserve2_init) > 0)
247 DBG("Disconnecting from cserve2.");
248 _server_disconnect();
254 evas_cserve2_use_get(void)
269 _server_dispatch(void)
273 Eina_List *l, *l_next;
277 msg = _server_read(&size);
281 EINA_LIST_FOREACH_SAFE(_requests, l, l_next, cr)
283 if (cr->rid != msg->rid) // dispatch this answer
286 _requests = eina_list_remove_list(_requests, l);
288 cr->cb(cr->data, msg);
299 _server_dispatch_until(unsigned int rid)
301 Eina_Bool done = EINA_FALSE;
305 if (_server_dispatch() == rid)
311 _image_opened_cb(void *data, const void *msg_received)
313 const Msg_Base *answer = msg_received;
314 const Msg_Opened *msg = msg_received;
315 Image_Entry *ie = data;
319 if (answer->type == CSERVE2_ERROR)
321 const Msg_Error *msg_error = msg_received;
322 ERR("Couldn't open image: '%s':'%s'; error: %d",
323 ie->file, ie->key, msg_error->error);
329 ie->w = msg->image.w;
330 ie->h = msg->image.h;
331 ie->flags.alpha = msg->image.alpha;
332 ie->loop_hint = msg->image.loop_hint;
333 ie->loop_count = msg->image.loop_count;
334 ie->frame_count = msg->image.frame_count;
338 _loaded_handle(Image_Entry *ie, const Msg_Loaded *msg)
340 Data_Entry *dentry = ie->data2;
343 shmpath = ((const char *)msg) + sizeof(*msg);
345 // dentry->shm.path = strdup(shmpath);
346 dentry->shm.mmap_offset = msg->shm.mmap_offset;
347 dentry->shm.use_offset = msg->shm.use_offset;
348 dentry->shm.mmap_size = msg->shm.mmap_size;
349 dentry->shm.image_size = msg->shm.image_size;
351 dentry->shm.f = eina_file_open(shmpath, EINA_TRUE);
359 dentry->shm.data = eina_file_map_new(dentry->shm.f, EINA_FILE_WILLNEED,
360 dentry->shm.mmap_offset,
361 dentry->shm.mmap_size);
363 if (!dentry->shm.data)
365 eina_file_close(dentry->shm.f);
372 RGBA_Image *im = (RGBA_Image *)ie;
373 im->image.data = evas_cserve2_image_data_get(ie);
374 ie->flags.alpha_sparse = msg->alpha_sparse;
375 ie->flags.loaded = EINA_TRUE;
376 im->image.no_free = 1;
381 _image_loaded_cb(void *data, const void *msg_received)
383 const Msg_Base *answer = msg_received;
384 const Msg_Loaded *msg = msg_received;
385 Image_Entry *ie = data;
392 if (answer->type == CSERVE2_ERROR)
394 const Msg_Error *msg_error = msg_received;
395 ERR("Couldn't load image: '%s':'%s'; error: %d",
396 ie->file, ie->key, msg_error->error);
402 _loaded_handle(ie, msg);
406 _image_preloaded_cb(void *data, const void *msg_received)
408 const Msg_Base *answer = msg_received;
409 Image_Entry *ie = data;
410 Data_Entry *dentry = ie->data2;
412 DBG("Received PRELOADED for RID: %d", answer->rid);
415 if (answer->type == CSERVE2_ERROR)
417 const Msg_Error *msg_error = msg_received;
418 ERR("Couldn't preload image: '%s':'%s'; error: %d",
419 ie->file, ie->key, msg_error->error);
420 dentry->preloaded_cb(data, EINA_FALSE);
421 dentry->preloaded_cb = NULL;
425 _loaded_handle(ie, msg_received);
427 if (dentry && (dentry->preloaded_cb))
429 dentry->preloaded_cb(data, EINA_TRUE);
430 dentry->preloaded_cb = NULL;
435 _build_absolute_path(const char *path, char buf[], int size)
446 strncpy(p, path, size);
447 else if (path[0] == '~')
449 const char *home = getenv("HOME");
452 strncpy(p, home, size);
458 strncpy(p, path + 2, size);
462 if (!getcwd(p, size))
469 strncpy(p, path, size);
476 _image_open_server_send(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt __UNUSED__)
481 char filebuf[PATH_MAX];
485 if (cserve2_init == 0)
487 ERR("Server not initialized.");
493 _build_absolute_path(file, filebuf, sizeof(filebuf));
495 fentry = calloc(1, sizeof(*fentry));
497 memset(&msg_open, 0, sizeof(msg_open));
499 fentry->file_id = ++_file_id;
500 if (fentry->file_id == 0)
501 fentry->file_id = ++_file_id;
503 flen = strlen(filebuf) + 1;
504 klen = strlen(key) + 1;
506 msg_open.base.rid = _next_rid();
507 msg_open.base.type = CSERVE2_OPEN;
508 msg_open.file_id = fentry->file_id;
509 msg_open.path_offset = 0;
510 msg_open.key_offset = flen;
512 size = sizeof(msg_open) + flen + klen;
514 if (!buf) return EINA_FALSE;
515 memcpy(buf, &msg_open, sizeof(msg_open));
516 memcpy(buf + sizeof(msg_open), filebuf, flen);
517 memcpy(buf + sizeof(msg_open) + flen, key, klen);
519 if (!_server_send(buf, size, _image_opened_cb, ie))
521 ERR("Couldn't send message to server.");
529 return msg_open.base.rid;
533 _image_setopts_server_send(Image_Entry *ie)
539 if (cserve2_init == 0)
544 dentry = calloc(1, sizeof(*dentry));
546 memset(&msg, 0, sizeof(msg));
547 dentry->image_id = ++_data_id;
548 if (dentry->image_id == 0)
549 dentry->image_id = ++_data_id;
551 msg.base.rid = _next_rid();
552 msg.base.type = CSERVE2_SETOPTS;
553 msg.file_id = fentry->file_id;
554 msg.image_id = dentry->image_id;
556 msg.opts.scale_down = ie->load_opts.scale_down_by;
557 msg.opts.dpi = ie->load_opts.dpi;
558 msg.opts.w = ie->load_opts.w;
559 msg.opts.h = ie->load_opts.h;
560 msg.opts.rx = ie->load_opts.region.x;
561 msg.opts.ry = ie->load_opts.region.y;
562 msg.opts.rw = ie->load_opts.region.w;
563 msg.opts.rh = ie->load_opts.region.h;
564 msg.opts.orientation = ie->load_opts.orientation;
566 if (!_server_send(&msg, sizeof(msg), 0, NULL))
575 _image_load_server_send(Image_Entry *ie)
580 if (cserve2_init == 0)
585 ERR("No data for opened file.");
591 memset(&msg, 0, sizeof(msg));
593 msg.base.rid = _next_rid();
594 msg.base.type = CSERVE2_LOAD;
595 msg.image_id = dentry->image_id;
597 if (!_server_send(&msg, sizeof(msg), _image_loaded_cb, ie))
604 _image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
609 if (cserve2_init == 0)
613 dentry->preloaded_cb = preloaded_cb;
615 memset(&msg, 0, sizeof(msg));
617 msg.base.rid = _next_rid();
618 msg.base.type = CSERVE2_PRELOAD;
619 msg.image_id = dentry->image_id;
621 if (!_server_send(&msg, sizeof(msg), _image_preloaded_cb, ie))
628 _image_close_server_send(Image_Entry *ie)
633 if (cserve2_init == 0)
643 Data_Entry *dentry = ie->data2;
644 if (dentry->shm.data)
645 eina_file_map_free(dentry->shm.f, dentry->shm.data);
647 eina_file_close(dentry->shm.f);
652 memset(&msg, 0, sizeof(msg));
653 msg.base.rid = _next_rid();
654 msg.base.type = CSERVE2_CLOSE;
655 msg.file_id = fentry->file_id;
660 if (!_server_send(&msg, sizeof(msg), NULL, NULL))
667 _image_unload_server_send(Image_Entry *ie)
672 if (cserve2_init == 0)
680 if (dentry->shm.data)
681 eina_file_map_free(dentry->shm.f, dentry->shm.data);
683 eina_file_close(dentry->shm.f);
685 // if (dentry->shm.path)
686 // free(dentry->shm.path);
687 memset(&msg, 0, sizeof(msg));
688 msg.base.rid = _next_rid();
689 msg.base.type = CSERVE2_UNLOAD;
690 msg.image_id = dentry->image_id;
695 if (!_server_send(&msg, sizeof(msg), NULL, NULL))
702 evas_cserve2_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
706 rid = _image_open_server_send(ie, file, key, lopt);
712 _image_setopts_server_send(ie);
714 // _server_dispatch_until(rid);
723 evas_cserve2_image_load_wait(Image_Entry *ie)
727 _server_dispatch_until(ie->open_rid);
729 return CSERVE2_GENERIC;
733 return CSERVE2_GENERIC;
737 evas_cserve2_image_data_load(Image_Entry *ie)
741 rid = _image_load_server_send(ie);
754 evas_cserve2_image_load_data_wait(Image_Entry *ie)
757 _server_dispatch_until(ie->load_rid);
761 evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
768 rid = _image_preload_server_send(ie, preloaded_cb);
772 ie->preload_rid = rid;
778 evas_cserve2_image_free(Image_Entry *ie)
783 if (!_image_close_server_send(ie))
784 WRN("Couldn't send close message to cserve2.");
788 evas_cserve2_image_unload(Image_Entry *ie)
793 if (!_image_unload_server_send(ie))
794 WRN("Couldn't send unload message to cserve2.");
798 evas_cserve2_dispatch(void)
800 _server_dispatch_until(0);
803 typedef struct _Glyph_Map Glyph_Map;
804 typedef struct _CS_Glyph_Out CS_Glyph_Out;
812 Font_Rend_Flags wanted_rend;
814 unsigned int rid; // open
816 Eina_Hash *glyphs_maps;
817 Fash_Glyph2 *fash[3]; // one per hinting value
819 Eina_Clist glyphs_queue;
820 int glyphs_queue_count;
821 Eina_Clist glyphs_used;
822 int glyphs_used_count;
824 Eina_Bool failed : 1;
839 RGBA_Font_Glyph_Out base;
840 Eina_Clist map_entry;
841 Eina_Clist used_list;
851 _font_entry_free(Font_Entry *fe)
855 for (i = 0; i < 3; i++)
857 fash_gl_free(fe->fash[i]);
859 eina_stringshare_del(fe->source);
860 eina_stringshare_del(fe->name);
861 eina_hash_free(fe->glyphs_maps);
866 _glyphs_map_free(Glyph_Map *m)
868 eina_file_map_free(m->map, m->data);
869 eina_file_close(m->map);
870 eina_stringshare_del(m->name);
875 _glyph_out_free(void *gl)
877 CS_Glyph_Out *glout = gl;
881 eina_clist_remove(&glout->map_entry);
882 if (eina_clist_empty(&glout->map->glyphs))
884 eina_hash_del(glout->map->fe->glyphs_maps, &glout->map->name,
886 _glyphs_map_free(glout->map);
894 _font_loaded_cb(void *data, const void *msg)
896 const Msg_Base *m = msg;
897 Font_Entry *fe = data;
901 if (m->type == CSERVE2_ERROR)
902 fe->failed = EINA_TRUE;
906 _font_load_server_send(Font_Entry *fe, Message_Type type)
909 int source_len, path_len, size;
911 unsigned int ret = 0;
912 void (*cb)(void *data, const void *msg) = NULL;
917 source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
918 path_len = eina_stringshare_strlen(fe->name) + 1;
920 size = sizeof(*msg) + path_len + source_len;
921 msg = calloc(1, size);
923 msg->base.rid = _next_rid();
924 msg->base.type = type;
926 msg->sourcelen = source_len;
927 msg->pathlen = path_len;
928 msg->rend_flags = fe->wanted_rend;
929 msg->size = fe->size;
932 buf = ((char *)msg) + sizeof(*msg);
933 memcpy(buf, fe->source, source_len);
935 memcpy(buf, fe->name, path_len);
937 if (type == CSERVE2_FONT_LOAD)
938 cb = _font_loaded_cb;
940 if (_server_send(msg, size, cb, fe))
949 evas_cserve2_font_load(const char *source, const char *name, int size, int dpi, Font_Rend_Flags wanted_rend)
953 fe = calloc(1, sizeof(Font_Entry));
954 if (!fe) return NULL;
956 fe->source = source ? eina_stringshare_add(source) : NULL;
957 fe->name = eina_stringshare_add(name);
960 fe->wanted_rend = wanted_rend;
962 if (!(fe->rid = _font_load_server_send(fe, CSERVE2_FONT_LOAD)))
964 eina_stringshare_del(fe->source);
965 eina_stringshare_del(fe->name);
970 fe->glyphs_maps = eina_hash_stringshared_new(NULL);
971 eina_clist_init(&fe->glyphs_queue);
972 eina_clist_init(&fe->glyphs_used);
978 evas_cserve2_font_free(Font_Entry *fe)
985 _font_load_server_send(fe, CSERVE2_FONT_UNLOAD);
987 _font_entry_free(fe);
993 Font_Hint_Flags hints;
995 } Glyph_Request_Data;
998 _glyph_request_cb(void *data, const void *msg)
1000 const Msg_Font_Glyphs_Loaded *resp = msg;
1001 Glyph_Request_Data *grd = data;
1002 Font_Entry *fe = grd->fe;
1003 unsigned int ncaches = 0;
1006 if (resp->base.type == CSERVE2_ERROR)
1012 buf = (const char *)resp + sizeof(*resp);
1013 while (ncaches < resp->ncaches)
1020 memcpy(&namelen, buf, sizeof(int));
1023 name = eina_stringshare_add_length(buf, namelen);
1026 memcpy(&nglyphs, buf, sizeof(int));
1029 map = eina_hash_find(fe->glyphs_maps, name);
1032 map = calloc(1, sizeof(*map));
1035 map->map = eina_file_open(name, EINA_TRUE);
1036 map->data = eina_file_map_all(map->map, EINA_FILE_WILLNEED);
1037 eina_clist_init(&map->glyphs);
1038 eina_hash_direct_add(fe->glyphs_maps, &map->name, map);
1041 eina_stringshare_del(name);
1045 unsigned int idx, offset, glsize;
1046 int rows, width, pitch, num_grays, pixel_mode;
1049 memcpy(&idx, buf, sizeof(int));
1051 memcpy(&offset, buf, sizeof(int));
1053 memcpy(&glsize, buf, sizeof(int));
1055 memcpy(&rows, buf, sizeof(int));
1057 memcpy(&width, buf, sizeof(int));
1059 memcpy(&pitch, buf, sizeof(int));
1061 memcpy(&num_grays, buf, sizeof(int));
1063 memcpy(&pixel_mode, buf, sizeof(int));
1066 gl = fash_gl_find(fe->fash[grd->hints], idx);
1068 gl->offset = offset;
1070 gl->base.bitmap.rows = rows;
1071 gl->base.bitmap.width = width;
1072 gl->base.bitmap.pitch = pitch;
1073 gl->base.bitmap.buffer = map->data + gl->offset;
1074 gl->base.bitmap.num_grays = num_grays;
1075 gl->base.bitmap.pixel_mode = pixel_mode;
1079 eina_clist_add_head(&map->glyphs, &gl->map_entry);
1091 _glyph_request_server_send(Font_Entry *fe, Font_Hint_Flags hints, Eina_Bool used)
1093 Msg_Font_Glyphs_Request *msg;
1094 Glyph_Request_Data *grd = NULL;
1095 int source_len, name_len, size, nglyphs;
1097 unsigned int *glyphs;
1098 unsigned int ret = 0;
1100 Eina_Clist *queue, *itr, *itr_next;
1103 source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
1104 name_len = eina_stringshare_strlen(fe->name) + 1;
1108 nglyphs = fe->glyphs_queue_count;
1109 queue = &fe->glyphs_queue;
1113 nglyphs = fe->glyphs_used_count;
1114 queue = &fe->glyphs_used;
1117 size = sizeof(*msg) + source_len + name_len + (nglyphs * sizeof(int));
1118 msg = calloc(1, size);
1120 msg->base.rid = _next_rid();
1122 msg->base.type = CSERVE2_FONT_GLYPHS_LOAD;
1124 msg->base.type = CSERVE2_FONT_GLYPHS_USED;
1126 msg->sourcelen = source_len;
1127 msg->pathlen = name_len;
1128 msg->rend_flags = fe->wanted_rend;
1129 msg->size = fe->size;
1132 msg->nglyphs = nglyphs;
1134 buf = ((char *)msg) + sizeof(*msg);
1135 memcpy(buf, fe->source, source_len);
1137 memcpy(buf, fe->name, name_len);
1139 glyphs = (unsigned int *)buf;
1141 EINA_CLIST_FOR_EACH_SAFE(itr, itr_next, queue)
1147 gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, map_entry);
1148 gl->rid = msg->base.rid;
1149 eina_clist_remove(&gl->map_entry);
1153 gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, used_list);
1154 gl->used = EINA_FALSE;
1155 eina_clist_remove(&gl->used_list);
1157 glyphs[nglyphs++] = gl->idx;
1160 fe->glyphs_queue_count = 0;
1162 fe->glyphs_used_count = 0;
1166 cb = _glyph_request_cb;
1167 grd = malloc(sizeof(*grd));
1169 grd->rid = msg->base.rid;
1175 if (_server_send(msg, size, cb, grd))
1176 ret = msg->base.rid;
1186 evas_cserve2_font_glyph_request(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1189 CS_Glyph_Out *glyph;
1192 _server_dispatch_until(0); /* dispatch anything pending just to avoid
1193 requesting glyphs for a font we may already
1194 know it failed loading, but don't block */
1199 fash = fe->fash[hints];
1202 fash = fash_gl_new(_glyph_out_free);
1203 fe->fash[hints] = fash;
1206 glyph = fash_gl_find(fash, idx);
1209 glyph = calloc(1, sizeof(*glyph));
1213 fash_gl_add(fash, idx, glyph);
1215 eina_clist_add_head(&fe->glyphs_queue, &glyph->map_entry);
1216 fe->glyphs_queue_count++;
1218 else if (!glyph->used)
1220 eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1221 fe->glyphs_used_count++;
1222 glyph->used = EINA_TRUE;
1225 /* crude way to manage a queue, but it will work for now */
1226 if (fe->glyphs_queue_count == 50)
1227 _glyph_request_server_send(fe, hints, EINA_FALSE);
1233 evas_cserve2_font_glyph_used(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1236 CS_Glyph_Out *glyph;
1239 _server_dispatch_until(0); /* dispatch anything pending just to avoid
1240 requesting glyphs for a font we may already
1241 know it failed loading, but don't block */
1246 fash = fe->fash[hints];
1250 glyph = fash_gl_find(fash, idx);
1251 /* If we found the glyph on client cache, we should also have at least
1263 eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1264 fe->glyphs_used_count++;
1265 glyph->used = EINA_TRUE;
1270 RGBA_Font_Glyph_Out *
1271 evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1279 /* quick hack, flush pending queue when we are asked for a bitmap */
1280 if (fe->glyphs_queue_count)
1281 _glyph_request_server_send(fe, hints, EINA_FALSE);
1283 if (fe->glyphs_used_count)
1284 _glyph_request_server_send(fe, hints, EINA_TRUE);
1286 fash = fe->fash[hints];
1289 // this should not happen really, so let the user know he fucked up
1290 system("format c:");
1294 out = fash_gl_find(fash, idx);
1297 // again, if we are asking for a bitmap we were supposed to already
1298 // have requested the glyph, it must be there
1302 _server_dispatch_until(out->rid);
1304 // promote shm and font entry in lru or something
1306 return &(out->base);