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, 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 ie->flags.loaded = EINA_TRUE;
373 ie->flags.alpha_sparse = msg->alpha_sparse;
378 _image_loaded_cb(void *data, const void *msg_received)
380 const Msg_Base *answer = msg_received;
381 const Msg_Loaded *msg = msg_received;
382 Image_Entry *ie = data;
389 if (answer->type == CSERVE2_ERROR)
391 const Msg_Error *msg_error = msg_received;
392 ERR("Couldn't load image: '%s':'%s'; error: %d",
393 ie->file, ie->key, msg_error->error);
399 _loaded_handle(ie, msg);
403 _image_preloaded_cb(void *data, const void *msg_received)
405 const Msg_Base *answer = msg_received;
406 Image_Entry *ie = data;
407 Data_Entry *dentry = ie->data2;
409 DBG("Received PRELOADED for RID: %d", answer->rid);
412 if (answer->type == CSERVE2_ERROR)
414 const Msg_Error *msg_error = msg_received;
415 ERR("Couldn't preload image: '%s':'%s'; error: %d",
416 ie->file, ie->key, msg_error->error);
417 dentry->preloaded_cb(data, EINA_FALSE);
418 dentry->preloaded_cb = NULL;
422 _loaded_handle(ie, msg_received);
424 if (dentry && (dentry->preloaded_cb))
426 dentry->preloaded_cb(data, EINA_TRUE);
427 dentry->preloaded_cb = NULL;
432 _build_absolute_path(const char *path, char buf[], int size)
443 strncpy(p, path, size);
444 else if (path[0] == '~')
446 const char *home = getenv("HOME");
449 strncpy(p, home, size);
455 strncpy(p, path + 2, size);
459 if (!getcwd(p, size))
466 strncpy(p, path, size);
473 _image_open_server_send(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt __UNUSED__)
478 char filebuf[PATH_MAX];
482 if (cserve2_init == 0)
484 ERR("Server not initialized.");
490 _build_absolute_path(file, filebuf, sizeof(filebuf));
492 fentry = calloc(1, sizeof(*fentry));
494 memset(&msg_open, 0, sizeof(msg_open));
496 fentry->file_id = ++_file_id;
497 if (fentry->file_id == 0)
498 fentry->file_id = ++_file_id;
500 flen = strlen(filebuf) + 1;
501 klen = strlen(key) + 1;
503 msg_open.base.rid = _next_rid();
504 msg_open.base.type = CSERVE2_OPEN;
505 msg_open.file_id = fentry->file_id;
506 msg_open.path_offset = 0;
507 msg_open.key_offset = flen;
509 size = sizeof(msg_open) + flen + klen;
511 if (!buf) return EINA_FALSE;
512 memcpy(buf, &msg_open, sizeof(msg_open));
513 memcpy(buf + sizeof(msg_open), filebuf, flen);
514 memcpy(buf + sizeof(msg_open) + flen, key, klen);
516 if (!_server_send(buf, size, _image_opened_cb, ie))
518 ERR("Couldn't send message to server.");
526 return msg_open.base.rid;
530 _image_setopts_server_send(Image_Entry *ie)
536 if (cserve2_init == 0)
541 dentry = calloc(1, sizeof(*dentry));
543 memset(&msg, 0, sizeof(msg));
544 dentry->image_id = ++_data_id;
545 if (dentry->image_id == 0)
546 dentry->image_id = ++_data_id;
548 msg.base.rid = _next_rid();
549 msg.base.type = CSERVE2_SETOPTS;
550 msg.file_id = fentry->file_id;
551 msg.image_id = dentry->image_id;
553 msg.opts.scale_down = ie->load_opts.scale_down_by;
554 msg.opts.dpi = ie->load_opts.dpi;
555 msg.opts.w = ie->load_opts.w;
556 msg.opts.h = ie->load_opts.h;
557 msg.opts.rx = ie->load_opts.region.x;
558 msg.opts.ry = ie->load_opts.region.y;
559 msg.opts.rw = ie->load_opts.region.w;
560 msg.opts.rh = ie->load_opts.region.h;
561 msg.opts.orientation = ie->load_opts.orientation;
563 if (!_server_send(&msg, sizeof(msg), 0, NULL))
572 _image_load_server_send(Image_Entry *ie)
577 if (cserve2_init == 0)
582 ERR("No data for opened file.");
588 memset(&msg, 0, sizeof(msg));
590 msg.base.rid = _next_rid();
591 msg.base.type = CSERVE2_LOAD;
592 msg.image_id = dentry->image_id;
594 if (!_server_send(&msg, sizeof(msg), _image_loaded_cb, ie))
601 _image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
606 if (cserve2_init == 0)
610 dentry->preloaded_cb = preloaded_cb;
612 memset(&msg, 0, sizeof(msg));
614 msg.base.rid = _next_rid();
615 msg.base.type = CSERVE2_PRELOAD;
616 msg.image_id = dentry->image_id;
618 if (!_server_send(&msg, sizeof(msg), _image_preloaded_cb, ie))
625 _image_close_server_send(Image_Entry *ie)
630 if (cserve2_init == 0)
640 Data_Entry *dentry = ie->data2;
641 if (dentry->shm.data)
642 eina_file_map_free(dentry->shm.f, dentry->shm.data);
644 eina_file_close(dentry->shm.f);
649 memset(&msg, 0, sizeof(msg));
650 msg.base.rid = _next_rid();
651 msg.base.type = CSERVE2_CLOSE;
652 msg.file_id = fentry->file_id;
657 if (!_server_send(&msg, sizeof(msg), NULL, NULL))
664 _image_unload_server_send(Image_Entry *ie)
669 if (cserve2_init == 0)
677 if (dentry->shm.data)
678 eina_file_map_free(dentry->shm.f, dentry->shm.data);
680 eina_file_close(dentry->shm.f);
682 // if (dentry->shm.path)
683 // free(dentry->shm.path);
684 memset(&msg, 0, sizeof(msg));
685 msg.base.rid = _next_rid();
686 msg.base.type = CSERVE2_UNLOAD;
687 msg.image_id = dentry->image_id;
692 if (!_server_send(&msg, sizeof(msg), NULL, NULL))
699 evas_cserve2_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
703 rid = _image_open_server_send(ie, file, key, lopt);
709 _image_setopts_server_send(ie);
711 // _server_dispatch_until(rid);
720 evas_cserve2_image_load_wait(Image_Entry *ie)
724 _server_dispatch_until(ie->open_rid);
726 return CSERVE2_GENERIC;
730 return CSERVE2_GENERIC;
734 evas_cserve2_image_data_load(Image_Entry *ie)
738 rid = _image_load_server_send(ie);
751 evas_cserve2_image_load_data_wait(Image_Entry *ie)
754 _server_dispatch_until(ie->load_rid);
758 evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
765 rid = _image_preload_server_send(ie, preloaded_cb);
769 ie->preload_rid = rid;
775 evas_cserve2_image_free(Image_Entry *ie)
780 if (!_image_close_server_send(ie))
781 WRN("Couldn't send close message to cserve2.");
785 evas_cserve2_image_unload(Image_Entry *ie)
790 if (!_image_unload_server_send(ie))
791 WRN("Couldn't send unload message to cserve2.");
795 evas_cserve2_dispatch(void)
797 _server_dispatch_until(0);
800 typedef struct _Glyph_Map Glyph_Map;
801 typedef struct _CS_Glyph_Out CS_Glyph_Out;
809 Font_Rend_Flags wanted_rend;
811 unsigned int rid; // open
813 Eina_Hash *glyphs_maps;
814 Fash_Glyph2 *fash[3]; // one per hinting value
816 Eina_Clist glyphs_queue;
817 int glyphs_queue_count;
818 Eina_Clist glyphs_used;
819 int glyphs_used_count;
821 Eina_Bool failed : 1;
836 RGBA_Font_Glyph_Out base;
837 Eina_Clist map_entry;
838 Eina_Clist used_list;
848 _font_entry_free(Font_Entry *fe)
852 for (i = 0; i < 3; i++)
854 fash_gl_free(fe->fash[i]);
856 eina_stringshare_del(fe->source);
857 eina_stringshare_del(fe->name);
858 eina_hash_free(fe->glyphs_maps);
863 _glyphs_map_free(Glyph_Map *m)
865 eina_file_map_free(m->map, m->data);
866 eina_file_close(m->map);
867 eina_stringshare_del(m->name);
872 _glyph_out_free(void *gl)
874 CS_Glyph_Out *glout = gl;
878 eina_clist_remove(&glout->map_entry);
879 if (eina_clist_empty(&glout->map->glyphs))
881 eina_hash_del(glout->map->fe->glyphs_maps, &glout->map->name,
883 _glyphs_map_free(glout->map);
891 _font_loaded_cb(void *data, const void *msg)
893 const Msg_Base *m = msg;
894 Font_Entry *fe = data;
898 if (m->type == CSERVE2_ERROR)
899 fe->failed = EINA_TRUE;
903 _font_load_server_send(Font_Entry *fe, Message_Type type)
906 int source_len, path_len, size;
908 unsigned int ret = 0;
909 void (*cb)(void *data, const void *msg) = NULL;
914 source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
915 path_len = eina_stringshare_strlen(fe->name) + 1;
917 size = sizeof(*msg) + path_len + source_len;
918 msg = calloc(1, size);
920 msg->base.rid = _next_rid();
921 msg->base.type = type;
923 msg->sourcelen = source_len;
924 msg->pathlen = path_len;
925 msg->rend_flags = fe->wanted_rend;
926 msg->size = fe->size;
929 buf = ((char *)msg) + sizeof(*msg);
930 memcpy(buf, fe->source, source_len);
932 memcpy(buf, fe->name, path_len);
934 if (type == CSERVE2_FONT_LOAD)
935 cb = _font_loaded_cb;
937 if (_server_send(msg, size, cb, fe))
946 evas_cserve2_font_load(const char *source, const char *name, int size, int dpi, Font_Rend_Flags wanted_rend)
950 fe = calloc(1, sizeof(Font_Entry));
951 if (!fe) return NULL;
953 fe->source = source ? eina_stringshare_add(source) : NULL;
954 fe->name = eina_stringshare_add(name);
957 fe->wanted_rend = wanted_rend;
959 if (!(fe->rid = _font_load_server_send(fe, CSERVE2_FONT_LOAD)))
961 eina_stringshare_del(fe->source);
962 eina_stringshare_del(fe->name);
967 fe->glyphs_maps = eina_hash_stringshared_new(NULL);
968 eina_clist_init(&fe->glyphs_queue);
969 eina_clist_init(&fe->glyphs_used);
975 evas_cserve2_font_free(Font_Entry *fe)
982 _font_load_server_send(fe, CSERVE2_FONT_UNLOAD);
984 _font_entry_free(fe);
990 Font_Hint_Flags hints;
992 } Glyph_Request_Data;
995 _glyph_request_cb(void *data, const void *msg)
997 const Msg_Font_Glyphs_Loaded *resp = msg;
998 Glyph_Request_Data *grd = data;
999 Font_Entry *fe = grd->fe;
1000 unsigned int ncaches = 0;
1003 if (resp->base.type == CSERVE2_ERROR)
1009 buf = (const char *)resp + sizeof(*resp);
1010 while (ncaches < resp->ncaches)
1017 memcpy(&namelen, buf, sizeof(int));
1020 name = eina_stringshare_add_length(buf, namelen);
1023 memcpy(&nglyphs, buf, sizeof(int));
1026 map = eina_hash_find(fe->glyphs_maps, name);
1029 map = calloc(1, sizeof(*map));
1032 map->map = eina_file_open(name, EINA_TRUE);
1033 map->data = eina_file_map_all(map->map, EINA_FILE_WILLNEED);
1034 eina_clist_init(&map->glyphs);
1035 eina_hash_direct_add(fe->glyphs_maps, &map->name, map);
1038 eina_stringshare_del(name);
1042 unsigned int idx, offset, glsize;
1043 int rows, width, pitch, num_grays, pixel_mode;
1046 memcpy(&idx, buf, sizeof(int));
1048 memcpy(&offset, buf, sizeof(int));
1050 memcpy(&glsize, buf, sizeof(int));
1052 memcpy(&rows, buf, sizeof(int));
1054 memcpy(&width, buf, sizeof(int));
1056 memcpy(&pitch, buf, sizeof(int));
1058 memcpy(&num_grays, buf, sizeof(int));
1060 memcpy(&pixel_mode, buf, sizeof(int));
1063 gl = fash_gl_find(fe->fash[grd->hints], idx);
1065 gl->offset = offset;
1067 gl->base.bitmap.rows = rows;
1068 gl->base.bitmap.width = width;
1069 gl->base.bitmap.pitch = pitch;
1070 gl->base.bitmap.buffer = map->data + gl->offset;
1071 gl->base.bitmap.num_grays = num_grays;
1072 gl->base.bitmap.pixel_mode = pixel_mode;
1076 eina_clist_add_head(&map->glyphs, &gl->map_entry);
1088 _glyph_request_server_send(Font_Entry *fe, Font_Hint_Flags hints, Eina_Bool used)
1090 Msg_Font_Glyphs_Request *msg;
1091 Glyph_Request_Data *grd = NULL;
1092 int source_len, name_len, size, nglyphs;
1094 unsigned int *glyphs;
1095 unsigned int ret = 0;
1097 Eina_Clist *queue, *itr, *itr_next;
1100 source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
1101 name_len = eina_stringshare_strlen(fe->name) + 1;
1105 nglyphs = fe->glyphs_queue_count;
1106 queue = &fe->glyphs_queue;
1110 nglyphs = fe->glyphs_used_count;
1111 queue = &fe->glyphs_used;
1114 size = sizeof(*msg) + source_len + name_len + (nglyphs * sizeof(int));
1115 msg = calloc(1, size);
1117 msg->base.rid = _next_rid();
1119 msg->base.type = CSERVE2_FONT_GLYPHS_LOAD;
1121 msg->base.type = CSERVE2_FONT_GLYPHS_USED;
1123 msg->sourcelen = source_len;
1124 msg->pathlen = name_len;
1125 msg->rend_flags = fe->wanted_rend;
1126 msg->size = fe->size;
1129 msg->nglyphs = nglyphs;
1131 buf = ((char *)msg) + sizeof(*msg);
1132 memcpy(buf, fe->source, source_len);
1134 memcpy(buf, fe->name, name_len);
1136 glyphs = (unsigned int *)buf;
1138 EINA_CLIST_FOR_EACH_SAFE(itr, itr_next, queue)
1144 gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, map_entry);
1145 gl->rid = msg->base.rid;
1146 eina_clist_remove(&gl->map_entry);
1150 gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, used_list);
1151 gl->used = EINA_FALSE;
1152 eina_clist_remove(&gl->used_list);
1154 glyphs[nglyphs++] = gl->idx;
1157 fe->glyphs_queue_count = 0;
1159 fe->glyphs_used_count = 0;
1163 cb = _glyph_request_cb;
1164 grd = malloc(sizeof(*grd));
1166 grd->rid = msg->base.rid;
1172 if (_server_send(msg, size, cb, grd))
1173 ret = msg->base.rid;
1183 evas_cserve2_font_glyph_request(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1186 CS_Glyph_Out *glyph;
1189 _server_dispatch_until(0); /* dispatch anything pending just to avoid
1190 requesting glyphs for a font we may already
1191 know it failed loading, but don't block */
1196 fash = fe->fash[hints];
1199 fash = fash_gl_new(_glyph_out_free);
1200 fe->fash[hints] = fash;
1203 glyph = fash_gl_find(fash, idx);
1206 glyph = calloc(1, sizeof(*glyph));
1210 fash_gl_add(fash, idx, glyph);
1212 eina_clist_add_head(&fe->glyphs_queue, &glyph->map_entry);
1213 fe->glyphs_queue_count++;
1215 else if (!glyph->used)
1217 eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1218 fe->glyphs_used_count++;
1219 glyph->used = EINA_TRUE;
1222 /* crude way to manage a queue, but it will work for now */
1223 if (fe->glyphs_queue_count == 50)
1224 _glyph_request_server_send(fe, hints, EINA_FALSE);
1230 evas_cserve2_font_glyph_used(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1233 CS_Glyph_Out *glyph;
1236 _server_dispatch_until(0); /* dispatch anything pending just to avoid
1237 requesting glyphs for a font we may already
1238 know it failed loading, but don't block */
1243 fash = fe->fash[hints];
1247 glyph = fash_gl_find(fash, idx);
1248 /* If we found the glyph on client cache, we should also have at least
1260 eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1261 fe->glyphs_used_count++;
1262 glyph->used = EINA_TRUE;
1267 RGBA_Font_Glyph_Out *
1268 evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1276 /* quick hack, flush pending queue when we are asked for a bitmap */
1277 if (fe->glyphs_queue_count)
1278 _glyph_request_server_send(fe, hints, EINA_FALSE);
1280 if (fe->glyphs_used_count)
1281 _glyph_request_server_send(fe, hints, EINA_TRUE);
1283 fash = fe->fash[hints];
1286 // this should not happen really, so let the user know he fucked up
1287 system("format c:");
1291 out = fash_gl_find(fash, idx);
1294 // again, if we are asking for a bitmap we were supposed to already
1295 // have requested the glyph, it must be there
1299 _server_dispatch_until(out->rid);
1301 // promote shm and font entry in lru or something
1303 return &(out->base);