evas/cserve2: Set image->flags.loaded on loaded_handle.
[profile/ivi/evas.git] / src / lib / cserve2 / evas_cs2_client.c
1 #include "config.h"
2
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <sys/un.h>
6
7 #include <sys/mman.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10
11 #include <Eina.h>
12
13 #include "evas_cs2.h"
14 #include "evas_cs2_private.h"
15 #include "evas_cs2_utils.h"
16
17 #ifdef EVAS_CSERVE2
18
19 typedef void (*Op_Callback)(void *data, const void *msg);
20
21 struct _File_Entry {
22    unsigned int file_id;
23 };
24
25 struct _Client_Request {
26    Message_Type type;
27    unsigned int rid;
28    Op_Callback cb;
29    void *data;
30 };
31
32 typedef struct _File_Entry File_Entry;
33 typedef struct _Client_Request Client_Request;
34
35 static int cserve2_init = 0;
36 static int socketfd = -1;
37
38 static unsigned int _rid_count = 0;
39 static unsigned int _file_id = 0;
40 static unsigned int _data_id = 0;
41
42 static Eina_List *_requests = NULL;
43
44 static struct sockaddr_un socksize;
45 #ifndef UNIX_PATH_MAX
46 #define UNIX_PATH_MAX sizeof(socksize.sun_path)
47 #endif
48
49 static void
50 _socket_path_set(char *path)
51 {
52    char *env;
53    char buf[UNIX_PATH_MAX];
54
55    env = getenv("EVAS_CSERVE2_SOCKET");
56    if (env && env[0])
57      {
58         strncpy(path, env, UNIX_PATH_MAX - 1);
59         return;
60      }
61
62    snprintf(buf, sizeof(buf), "/tmp/.evas-cserve2-%x.socket", (int)getuid());
63    /* FIXME: check we can actually create this socket */
64    strcpy(path, buf);
65 #if 0   
66    env = getenv("XDG_RUNTIME_DIR");
67    if (!env || !env[0])
68      {
69         env = getenv("HOME");
70         if (!env || !env[0])
71           {
72              env = getenv("TMPDIR");
73              if (!env || !env[0])
74                env = "/tmp";
75           }
76      }
77
78    snprintf(buf, sizeof(buf), "%s/evas-cserve2-%x.socket", env, getuid());
79    /* FIXME: check we can actually create this socket */
80    strcpy(path, buf);
81 #endif   
82 }
83
84 static Eina_Bool
85 _server_connect(void)
86 {
87    int s, len;
88    struct sockaddr_un remote;
89
90    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
91      {
92         ERR("socket");
93         return EINA_FALSE;
94      }
95
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)
100      {
101         ERR("connect");
102         return EINA_FALSE;
103      }
104
105    fcntl(s, F_SETFL, O_NONBLOCK);
106
107    socketfd = s;
108
109    DBG("connected to cserve2 server.");
110    return EINA_TRUE;
111 }
112
113 static void
114 _server_disconnect(void)
115 {
116    close(socketfd);
117    socketfd = -1;
118 }
119
120 static void
121 _request_answer_add(Message_Type type, unsigned int rid, Op_Callback cb, void *data)
122 {
123    Client_Request *cr = calloc(1, sizeof(*cr));
124
125    cr->type = type;
126    cr->rid = rid;
127    cr->cb = cb;
128    cr->data = data;
129
130    _requests = eina_list_append(_requests, cr);
131 }
132
133 static Eina_Bool
134 _server_safe_send(int fd, const void *data, int size)
135 {
136    int sent = 0;
137    ssize_t ret;
138    const char *msg = data;
139
140    while (sent < size)
141      {
142         ret = send(fd, msg + sent, size - sent, MSG_NOSIGNAL);
143         if (ret < 0)
144           {
145              if ((errno == EAGAIN) || (errno == EINTR))
146                continue;
147              return EINA_FALSE;
148           }
149         sent += ret;
150      }
151
152    return EINA_TRUE;
153 }
154
155 static Eina_Bool
156 _server_send(const void *buf, int size, Op_Callback cb, void *data)
157 {
158    const Msg_Base *msg;
159    if (!_server_safe_send(socketfd, &size, sizeof(size)))
160      {
161         ERR("Couldn't send message size to server.");
162         return EINA_FALSE;
163      }
164    if (!_server_safe_send(socketfd, buf, size))
165      {
166         ERR("Couldn't send message body to server.");
167         return EINA_FALSE;
168      }
169
170    msg = buf;
171    switch (msg->type)
172      {
173       case CSERVE2_OPEN:
174       case CSERVE2_SETOPTS:
175       case CSERVE2_LOAD:
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);
180          break;
181       default:
182          break;
183      }
184
185    return EINA_TRUE;
186 }
187
188 static int sr_size = 0;
189 static int sr_got = 0;
190 static char *sr_buf = NULL;
191
192 static void *
193 _server_read(int *size)
194 {
195    int n;
196    void *ret;
197
198    if (sr_size)
199      goto get_data;
200
201    n = recv(socketfd, &sr_size, sizeof(sr_size), 0);
202    if (n < 0)
203      return NULL;
204
205    sr_buf = malloc(sr_size);
206
207 get_data:
208    n = recv(socketfd, sr_buf + sr_got, sr_size - sr_got, 0);
209    if (n < 0)
210      return NULL;
211
212    sr_got += n;
213    if (sr_got < sr_size)
214      return NULL;
215
216    *size = sr_size;
217    sr_size = 0;
218    sr_got = 0;
219    ret = sr_buf;
220    sr_buf = NULL;
221
222    return ret;
223 }
224
225 int
226 evas_cserve2_init(void)
227 {
228    if (cserve2_init++)
229      return cserve2_init;
230
231    DBG("Connecting to cserve2.");
232    if (!_server_connect())
233      {
234         cserve2_init = 0;
235         return 0;
236      }
237
238    return cserve2_init;
239 }
240
241 int
242 evas_cserve2_shutdown(void)
243 {
244    if ((--cserve2_init) > 0)
245      return cserve2_init;
246
247    DBG("Disconnecting from cserve2.");
248    _server_disconnect();
249
250    return cserve2_init;
251 }
252
253 int
254 evas_cserve2_use_get(void)
255 {
256    return cserve2_init;
257 }
258
259 static unsigned int
260 _next_rid(void)
261 {
262    if (!_rid_count)
263      _rid_count++;
264
265    return _rid_count++;
266 }
267
268 static unsigned int
269 _server_dispatch(void)
270 {
271    int size;
272    unsigned int rid;
273    Eina_List *l, *l_next;
274    Client_Request *cr;
275    Msg_Base *msg;
276
277    msg = _server_read(&size);
278    if (!msg)
279      return 0;
280
281    EINA_LIST_FOREACH_SAFE(_requests, l, l_next, cr)
282      {
283         if (cr->rid != msg->rid) // dispatch this answer
284           continue;
285
286         _requests = eina_list_remove_list(_requests, l);
287         if (cr->cb)
288           cr->cb(cr->data, msg);
289         free(cr);
290      }
291
292    rid = msg->rid;
293    free(msg);
294
295    return rid;
296 }
297
298 static void
299 _server_dispatch_until(unsigned int rid)
300 {
301    Eina_Bool done = EINA_FALSE;
302
303    while (!done)
304      {
305         if (_server_dispatch() == rid)
306           done = EINA_TRUE;
307      }
308 }
309
310 static void
311 _image_opened_cb(void *data, const void *msg_received)
312 {
313    const Msg_Base *answer = msg_received;
314    const Msg_Opened *msg = msg_received;
315    Image_Entry *ie = data;
316
317    ie->open_rid = 0;
318
319    if (answer->type == CSERVE2_ERROR)
320      {
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);
324         free(ie->data1);
325         ie->data1 = NULL;
326         return;
327      }
328
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;
335 }
336
337 static void
338 _loaded_handle(Image_Entry *ie, const Msg_Loaded *msg)
339 {
340    Data_Entry *dentry = ie->data2;
341    const char *shmpath;
342
343    shmpath = ((const char *)msg) + sizeof(*msg);
344
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;
350
351    dentry->shm.f = eina_file_open(shmpath, EINA_TRUE);
352    if (!dentry->shm.f)
353      {
354         free(dentry);
355         ie->data2 = NULL;
356         return;
357      }
358
359    dentry->shm.data = eina_file_map_new(dentry->shm.f, EINA_FILE_WILLNEED,
360                                         dentry->shm.mmap_offset,
361                                         dentry->shm.mmap_size);
362
363    if (!dentry->shm.data)
364      {
365         eina_file_close(dentry->shm.f);
366         free(dentry);
367         ie->data2 = NULL;
368      }
369
370    if (ie->data2)
371      {
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;
377      }
378 }
379
380 static void
381 _image_loaded_cb(void *data, const void *msg_received)
382 {
383    const Msg_Base *answer = msg_received;
384    const Msg_Loaded *msg = msg_received;
385    Image_Entry *ie = data;
386
387    ie->load_rid = 0;
388
389    if (!ie->data2)
390      return;
391
392    if (answer->type == CSERVE2_ERROR)
393      {
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);
397         free(ie->data2);
398         ie->data2 = NULL;
399         return;
400      }
401
402    _loaded_handle(ie, msg);
403 }
404
405 static void
406 _image_preloaded_cb(void *data, const void *msg_received)
407 {
408    const Msg_Base *answer = msg_received;
409    Image_Entry *ie = data;
410    Data_Entry *dentry = ie->data2;
411
412    DBG("Received PRELOADED for RID: %d", answer->rid);
413    ie->preload_rid = 0;
414
415    if (answer->type == CSERVE2_ERROR)
416      {
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;
422         return;
423      }
424
425    _loaded_handle(ie, msg_received);
426
427    if (dentry && (dentry->preloaded_cb))
428      {
429         dentry->preloaded_cb(data, EINA_TRUE);
430         dentry->preloaded_cb = NULL;
431      }
432 }
433
434 static const char *
435 _build_absolute_path(const char *path, char buf[], int size)
436 {
437    char *p;
438    int len;
439
440    if (!path)
441      return NULL;
442
443    p = buf;
444
445    if (path[0] == '/')
446      strncpy(p, path, size);
447    else if (path[0] == '~')
448      {
449         const char *home = getenv("HOME");
450         if (!home)
451           return NULL;
452         strncpy(p, home, size);
453         len = strlen(p);
454         size -= len + 1;
455         p += len;
456         p[0] = '/';
457         p++;
458         strncpy(p, path + 2, size);
459      }
460    else
461      {
462         if (!getcwd(p, size))
463           return NULL;
464         len = strlen(p);
465         size -= len + 1;
466         p += len;
467         p[0] = '/';
468         p++;
469         strncpy(p, path, size);
470      }
471
472    return buf;
473 }
474
475 static unsigned int
476 _image_open_server_send(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt __UNUSED__)
477 {
478    int flen, klen;
479    int size;
480    char *buf;
481    char filebuf[PATH_MAX];
482    Msg_Open msg_open;
483    File_Entry *fentry;
484
485    if (cserve2_init == 0)
486      {
487         ERR("Server not initialized.");
488         return 0;
489      }
490
491    if (!key) key = "";
492
493    _build_absolute_path(file, filebuf, sizeof(filebuf));
494
495    fentry = calloc(1, sizeof(*fentry));
496
497    memset(&msg_open, 0, sizeof(msg_open));
498
499    fentry->file_id = ++_file_id;
500    if (fentry->file_id == 0)
501      fentry->file_id = ++_file_id;
502
503    flen = strlen(filebuf) + 1;
504    klen = strlen(key) + 1;
505
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;
511
512    size = sizeof(msg_open) + flen + klen;
513    buf = malloc(size);
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);
518
519    if (!_server_send(buf, size, _image_opened_cb, ie))
520      {
521         ERR("Couldn't send message to server.");
522         free(buf);
523         return 0;
524      }
525
526    free(buf);
527    ie->data1 = fentry;
528
529    return msg_open.base.rid;
530 }
531
532 unsigned int
533 _image_setopts_server_send(Image_Entry *ie)
534 {
535    File_Entry *fentry;
536    Data_Entry *dentry;
537    Msg_Setopts msg;
538
539    if (cserve2_init == 0)
540      return 0;
541
542    fentry = ie->data1;
543
544    dentry = calloc(1, sizeof(*dentry));
545
546    memset(&msg, 0, sizeof(msg));
547    dentry->image_id = ++_data_id;
548    if (dentry->image_id == 0)
549      dentry->image_id = ++_data_id;
550
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;
555
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;
565
566    if (!_server_send(&msg, sizeof(msg), 0, NULL))
567      return 0;
568
569    ie->data2 = dentry;
570
571    return msg.base.rid;
572 }
573
574 unsigned int
575 _image_load_server_send(Image_Entry *ie)
576 {
577    Data_Entry *dentry;
578    Msg_Load msg;
579
580    if (cserve2_init == 0)
581      return 0;
582
583    if (!ie->data1)
584      {
585         ERR("No data for opened file.");
586         return 0;
587      }
588
589    dentry = ie->data2;
590
591    memset(&msg, 0, sizeof(msg));
592
593    msg.base.rid = _next_rid();
594    msg.base.type = CSERVE2_LOAD;
595    msg.image_id = dentry->image_id;
596
597    if (!_server_send(&msg, sizeof(msg), _image_loaded_cb, ie))
598      return 0;
599
600    return msg.base.rid;
601 }
602
603 unsigned int
604 _image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
605 {
606    Data_Entry *dentry;
607    Msg_Preload msg;
608
609    if (cserve2_init == 0)
610      return 0;
611
612    dentry = ie->data2;
613    dentry->preloaded_cb = preloaded_cb;
614
615    memset(&msg, 0, sizeof(msg));
616
617    msg.base.rid = _next_rid();
618    msg.base.type = CSERVE2_PRELOAD;
619    msg.image_id = dentry->image_id;
620
621    if (!_server_send(&msg, sizeof(msg), _image_preloaded_cb, ie))
622      return 0;
623
624    return msg.base.rid;
625 }
626
627 unsigned int
628 _image_close_server_send(Image_Entry *ie)
629 {
630    Msg_Close msg;
631    File_Entry *fentry;
632
633    if (cserve2_init == 0)
634      return 0;
635
636    if (!ie->data1)
637      return 0;
638
639    fentry = ie->data1;
640
641    if (ie->data2)
642      {
643         Data_Entry *dentry = ie->data2;
644         if (dentry->shm.data)
645           eina_file_map_free(dentry->shm.f, dentry->shm.data);
646         if (dentry->shm.f)
647           eina_file_close(dentry->shm.f);
648         free(ie->data2);
649         ie->data2 = NULL;
650      }
651
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;
656
657    free(fentry);
658    ie->data1 = NULL;
659
660    if (!_server_send(&msg, sizeof(msg), NULL, NULL))
661      return 0;
662
663    return msg.base.rid;
664 }
665
666 unsigned int
667 _image_unload_server_send(Image_Entry *ie)
668 {
669    Msg_Unload msg;
670    Data_Entry *dentry;
671
672    if (cserve2_init == 0)
673      return 0;
674
675    if (!ie->data2)
676      return 0;
677
678    dentry = ie->data2;
679
680    if (dentry->shm.data)
681      eina_file_map_free(dentry->shm.f, dentry->shm.data);
682    if (dentry->shm.f)
683      eina_file_close(dentry->shm.f);
684
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;
691
692    free(dentry);
693    ie->data2 = NULL;
694
695    if (!_server_send(&msg, sizeof(msg), NULL, NULL))
696      return 0;
697
698    return msg.base.rid;
699 }
700
701 Eina_Bool
702 evas_cserve2_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
703 {
704    unsigned int rid;
705
706    rid = _image_open_server_send(ie, file, key, lopt);
707    if (!rid)
708      return EINA_FALSE;
709
710    ie->open_rid = rid;
711
712    _image_setopts_server_send(ie);
713
714    // _server_dispatch_until(rid);
715
716    if (ie->data1)
717      return EINA_TRUE;
718    else
719      return EINA_FALSE;
720 }
721
722 int
723 evas_cserve2_image_load_wait(Image_Entry *ie)
724 {
725    if (ie->open_rid)
726      {
727         _server_dispatch_until(ie->open_rid);
728         if (!ie->data1)
729           return CSERVE2_GENERIC;
730         return CSERVE2_NONE;
731      }
732    else
733      return CSERVE2_GENERIC;
734 }
735
736 Eina_Bool
737 evas_cserve2_image_data_load(Image_Entry *ie)
738 {
739    unsigned int rid;
740
741    rid = _image_load_server_send(ie);
742    if (!rid)
743      return EINA_FALSE;
744
745    ie->load_rid = rid;
746
747    if (ie->data2)
748      return EINA_TRUE;
749    else
750      return EINA_FALSE;
751 }
752
753 void
754 evas_cserve2_image_load_data_wait(Image_Entry *ie)
755 {
756    if (ie->load_rid)
757      _server_dispatch_until(ie->load_rid);
758 }
759
760 Eina_Bool
761 evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
762 {
763    unsigned int rid;
764
765    if (!ie->data1)
766      return EINA_FALSE;
767
768    rid = _image_preload_server_send(ie, preloaded_cb);
769    if (!rid)
770      return EINA_FALSE;
771
772    ie->preload_rid = rid;
773
774    return EINA_FALSE;
775 }
776
777 void
778 evas_cserve2_image_free(Image_Entry *ie)
779 {
780    if (!ie->data1)
781      return;
782
783    if (!_image_close_server_send(ie))
784      WRN("Couldn't send close message to cserve2.");
785 }
786
787 void
788 evas_cserve2_image_unload(Image_Entry *ie)
789 {
790    if (!ie->data2)
791      return;
792
793    if (!_image_unload_server_send(ie))
794      WRN("Couldn't send unload message to cserve2.");
795 }
796
797 void
798 evas_cserve2_dispatch(void)
799 {
800    _server_dispatch_until(0);
801 }
802
803 typedef struct _Glyph_Map Glyph_Map;
804 typedef struct _CS_Glyph_Out CS_Glyph_Out;
805
806 struct _Font_Entry
807 {
808    const char *source;
809    const char *name;
810    unsigned int size;
811    unsigned int dpi;
812    Font_Rend_Flags wanted_rend;
813
814    unsigned int rid; // open
815
816    Eina_Hash *glyphs_maps;
817    Fash_Glyph2 *fash[3]; // one per hinting value
818
819    Eina_Clist glyphs_queue;
820    int glyphs_queue_count;
821    Eina_Clist glyphs_used;
822    int glyphs_used_count;
823
824    Eina_Bool failed : 1;
825 };
826
827 struct _Glyph_Map
828 {
829    Font_Entry *fe;
830    const char *name;
831    unsigned int size;
832    Eina_File *map;
833    unsigned char *data;
834    Eina_Clist glyphs;
835 };
836
837 struct _CS_Glyph_Out
838 {
839    RGBA_Font_Glyph_Out base;
840    Eina_Clist map_entry;
841    Eina_Clist used_list;
842    unsigned int idx;
843    unsigned int rid;
844    Glyph_Map *map;
845    unsigned int offset;
846    unsigned int size;
847    Eina_Bool used;
848 };
849
850 static void
851 _font_entry_free(Font_Entry *fe)
852 {
853    int i;
854
855    for (i = 0; i < 3; i++)
856      if (fe->fash[i])
857        fash_gl_free(fe->fash[i]);
858
859    eina_stringshare_del(fe->source);
860    eina_stringshare_del(fe->name);
861    eina_hash_free(fe->glyphs_maps);
862    free(fe);
863 }
864
865 static void
866 _glyphs_map_free(Glyph_Map *m)
867 {
868    eina_file_map_free(m->map, m->data);
869    eina_file_close(m->map);
870    eina_stringshare_del(m->name);
871    free(m);
872 }
873
874 static void
875 _glyph_out_free(void *gl)
876 {
877    CS_Glyph_Out *glout = gl;
878
879    if (glout->map)
880      {
881         eina_clist_remove(&glout->map_entry);
882         if (eina_clist_empty(&glout->map->glyphs))
883           {
884              eina_hash_del(glout->map->fe->glyphs_maps, &glout->map->name,
885                            NULL);
886              _glyphs_map_free(glout->map);
887           }
888      }
889
890    free(glout);
891 }
892
893 static void
894 _font_loaded_cb(void *data, const void *msg)
895 {
896    const Msg_Base *m = msg;
897    Font_Entry *fe = data;
898
899    fe->rid = 0;
900
901    if (m->type == CSERVE2_ERROR)
902      fe->failed = EINA_TRUE;
903 }
904
905 static unsigned int
906 _font_load_server_send(Font_Entry *fe, Message_Type type)
907 {
908    Msg_Font_Load *msg;
909    int source_len, path_len, size;
910    char *buf;
911    unsigned int ret = 0;
912    void (*cb)(void *data, const void *msg) = NULL;
913
914    if (!cserve2_init)
915      return 0;
916
917    source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
918    path_len = eina_stringshare_strlen(fe->name) + 1;
919
920    size = sizeof(*msg) + path_len + source_len;
921    msg = calloc(1, size);
922
923    msg->base.rid = _next_rid();
924    msg->base.type = type;
925
926    msg->sourcelen = source_len;
927    msg->pathlen = path_len;
928    msg->rend_flags = fe->wanted_rend;
929    msg->size = fe->size;
930    msg->dpi = fe->dpi;
931
932    buf = ((char *)msg) + sizeof(*msg);
933    memcpy(buf, fe->source, source_len);
934    buf += source_len;
935    memcpy(buf, fe->name, path_len);
936
937    if (type == CSERVE2_FONT_LOAD)
938      cb = _font_loaded_cb;
939
940    if (_server_send(msg, size, cb, fe))
941      ret = msg->base.rid;
942
943    free(msg);
944
945    return ret;
946 }
947
948 Font_Entry *
949 evas_cserve2_font_load(const char *source, const char *name, int size, int dpi, Font_Rend_Flags wanted_rend)
950 {
951    Font_Entry *fe;
952
953    fe = calloc(1, sizeof(Font_Entry));
954    if (!fe) return NULL;
955
956    fe->source = source ? eina_stringshare_add(source) : NULL;
957    fe->name = eina_stringshare_add(name);
958    fe->size = size;
959    fe->dpi = dpi;
960    fe->wanted_rend = wanted_rend;
961
962    if (!(fe->rid = _font_load_server_send(fe, CSERVE2_FONT_LOAD)))
963      {
964         eina_stringshare_del(fe->source);
965         eina_stringshare_del(fe->name);
966         free(fe);
967         return NULL;
968      }
969
970    fe->glyphs_maps = eina_hash_stringshared_new(NULL);
971    eina_clist_init(&fe->glyphs_queue);
972    eina_clist_init(&fe->glyphs_used);
973
974    return fe;
975 }
976
977 void
978 evas_cserve2_font_free(Font_Entry *fe)
979 {
980    if (!fe) return;
981
982    if (fe->failed)
983      return;
984
985    _font_load_server_send(fe, CSERVE2_FONT_UNLOAD);
986
987    _font_entry_free(fe);
988 }
989
990 typedef struct
991 {
992    Font_Entry *fe;
993    Font_Hint_Flags hints;
994    unsigned int rid;
995 } Glyph_Request_Data;
996
997 static void
998 _glyph_request_cb(void *data, const void *msg)
999 {
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;
1004    const char *buf;
1005
1006    if (resp->base.type == CSERVE2_ERROR)
1007      {
1008         free(grd);
1009         return;
1010      }
1011
1012    buf = (const char *)resp + sizeof(*resp);
1013    while (ncaches < resp->ncaches)
1014      {
1015         int i = 0, nglyphs;
1016         int namelen;
1017         const char *name;
1018         Glyph_Map *map;
1019
1020         memcpy(&namelen, buf, sizeof(int));
1021         buf += sizeof(int);
1022
1023         name = eina_stringshare_add_length(buf, namelen);
1024         buf += namelen;
1025
1026         memcpy(&nglyphs, buf, sizeof(int));
1027         buf += sizeof(int);
1028
1029         map = eina_hash_find(fe->glyphs_maps, name);
1030         if (!map)
1031           {
1032              map = calloc(1, sizeof(*map));
1033              map->fe = fe;
1034              map->name = name;
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);
1039           }
1040         else
1041           eina_stringshare_del(name);
1042
1043         while (i < nglyphs)
1044           {
1045              unsigned int idx, offset, glsize;
1046              int rows, width, pitch, num_grays, pixel_mode;
1047              CS_Glyph_Out *gl;
1048
1049              memcpy(&idx, buf, sizeof(int));
1050              buf += sizeof(int);
1051              memcpy(&offset, buf, sizeof(int));
1052              buf += sizeof(int);
1053              memcpy(&glsize, buf, sizeof(int));
1054              buf += sizeof(int);
1055              memcpy(&rows, buf, sizeof(int));
1056              buf += sizeof(int);
1057              memcpy(&width, buf, sizeof(int));
1058              buf += sizeof(int);
1059              memcpy(&pitch, buf, sizeof(int));
1060              buf += sizeof(int);
1061              memcpy(&num_grays, buf, sizeof(int));
1062              buf += sizeof(int);
1063              memcpy(&pixel_mode, buf, sizeof(int));
1064              buf += sizeof(int);
1065
1066              gl = fash_gl_find(fe->fash[grd->hints], idx);
1067              gl->map = map;
1068              gl->offset = offset;
1069              gl->size = glsize;
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;
1076
1077              gl->rid = 0;
1078
1079              eina_clist_add_head(&map->glyphs, &gl->map_entry);
1080
1081              i++;
1082           }
1083
1084         ncaches++;
1085      }
1086
1087    free(grd);
1088 }
1089
1090 static unsigned int
1091 _glyph_request_server_send(Font_Entry *fe, Font_Hint_Flags hints, Eina_Bool used)
1092 {
1093    Msg_Font_Glyphs_Request *msg;
1094    Glyph_Request_Data *grd = NULL;
1095    int source_len, name_len, size, nglyphs;
1096    char *buf;
1097    unsigned int *glyphs;
1098    unsigned int ret = 0;
1099    Op_Callback cb;
1100    Eina_Clist *queue, *itr, *itr_next;
1101
1102
1103    source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
1104    name_len = eina_stringshare_strlen(fe->name) + 1;
1105
1106    if (!used)
1107      {
1108         nglyphs = fe->glyphs_queue_count;
1109         queue = &fe->glyphs_queue;
1110      }
1111    else
1112      {
1113         nglyphs = fe->glyphs_used_count;
1114         queue = &fe->glyphs_used;
1115      }
1116
1117    size = sizeof(*msg) + source_len + name_len + (nglyphs * sizeof(int));
1118    msg = calloc(1, size);
1119
1120    msg->base.rid = _next_rid();
1121    if (!used)
1122      msg->base.type = CSERVE2_FONT_GLYPHS_LOAD;
1123    else
1124      msg->base.type = CSERVE2_FONT_GLYPHS_USED;
1125
1126    msg->sourcelen = source_len;
1127    msg->pathlen = name_len;
1128    msg->rend_flags = fe->wanted_rend;
1129    msg->size = fe->size;
1130    msg->dpi = fe->dpi;
1131    msg->hint = hints;
1132    msg->nglyphs = nglyphs;
1133
1134    buf = ((char *)msg) + sizeof(*msg);
1135    memcpy(buf, fe->source, source_len);
1136    buf += source_len;
1137    memcpy(buf, fe->name, name_len);
1138    buf += name_len;
1139    glyphs = (unsigned int *)buf;
1140    nglyphs = 0;
1141    EINA_CLIST_FOR_EACH_SAFE(itr, itr_next, queue)
1142      {
1143         CS_Glyph_Out *gl;
1144
1145         if (!used)
1146           {
1147              gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, map_entry);
1148              gl->rid = msg->base.rid;
1149              eina_clist_remove(&gl->map_entry);
1150           }
1151         else
1152           {
1153              gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, used_list);
1154              gl->used = EINA_FALSE;
1155              eina_clist_remove(&gl->used_list);
1156           }
1157         glyphs[nglyphs++] = gl->idx;
1158      }
1159    if (!used)
1160      fe->glyphs_queue_count = 0;
1161    else
1162      fe->glyphs_used_count = 0;
1163
1164    if (!used)
1165      {
1166         cb = _glyph_request_cb;
1167         grd = malloc(sizeof(*grd));
1168         grd->fe = fe;
1169         grd->rid = msg->base.rid;
1170         grd->hints = hints;
1171      }
1172    else
1173      cb = NULL;
1174
1175    if (_server_send(msg, size, cb, grd))
1176      ret = msg->base.rid;
1177    else
1178      free(grd);
1179
1180    free(msg);
1181
1182    return ret;
1183 }
1184
1185 Eina_Bool
1186 evas_cserve2_font_glyph_request(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1187 {
1188    Fash_Glyph2 *fash;
1189    CS_Glyph_Out *glyph;
1190
1191    if (fe->rid)
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 */
1195
1196    if (fe->failed)
1197      return EINA_FALSE;
1198
1199    fash = fe->fash[hints];
1200    if (!fash)
1201      {
1202         fash = fash_gl_new(_glyph_out_free);
1203         fe->fash[hints] = fash;
1204      }
1205
1206    glyph = fash_gl_find(fash, idx);
1207    if (!glyph)
1208      {
1209         glyph = calloc(1, sizeof(*glyph));
1210
1211         glyph->idx = idx;
1212
1213         fash_gl_add(fash, idx, glyph);
1214
1215         eina_clist_add_head(&fe->glyphs_queue, &glyph->map_entry);
1216         fe->glyphs_queue_count++;
1217      }
1218    else if (!glyph->used)
1219      {
1220         eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1221         fe->glyphs_used_count++;
1222         glyph->used = EINA_TRUE;
1223      }
1224
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);
1228
1229    return EINA_TRUE;
1230 }
1231
1232 Eina_Bool
1233 evas_cserve2_font_glyph_used(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1234 {
1235    Fash_Glyph2 *fash;
1236    CS_Glyph_Out *glyph;
1237
1238    if (fe->rid)
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 */
1242
1243    if (fe->failed)
1244      return EINA_FALSE;
1245
1246    fash = fe->fash[hints];
1247    if (!fash)
1248      return EINA_FALSE;
1249
1250    glyph = fash_gl_find(fash, idx);
1251    /* If we found the glyph on client cache, we should also have at least
1252     * its request done.
1253     */
1254    if (!glyph)
1255      return EINA_FALSE;
1256
1257    if (!glyph->map)
1258      return EINA_TRUE;
1259
1260    if (glyph->used)
1261      return EINA_TRUE;
1262
1263    eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1264    fe->glyphs_used_count++;
1265    glyph->used = EINA_TRUE;
1266
1267    return EINA_TRUE;
1268 }
1269
1270 RGBA_Font_Glyph_Out *
1271 evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1272 {
1273    Fash_Glyph2 *fash;
1274    CS_Glyph_Out *out;
1275
1276    if (fe->failed)
1277      return NULL;
1278
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);
1282
1283    if (fe->glyphs_used_count)
1284      _glyph_request_server_send(fe, hints, EINA_TRUE);
1285
1286    fash = fe->fash[hints];
1287    if (!fash)
1288      {
1289         // this should not happen really, so let the user know he fucked up
1290         system("format c:");
1291         return NULL;
1292      }
1293
1294    out = fash_gl_find(fash, idx);
1295    if (!out)
1296      {
1297         // again, if we are asking for a bitmap we were supposed to already
1298         // have requested the glyph, it must be there
1299         return NULL;
1300      }
1301    if (out->rid)
1302      _server_dispatch_until(out->rid);
1303
1304    // promote shm and font entry in lru or something
1305
1306    return &(out->base);
1307 }
1308
1309 #endif