Set load options in the SETOPTS message
[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, 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         ie->flags.loaded = EINA_TRUE;
373         ie->flags.alpha_sparse = msg->alpha_sparse;
374      }
375 }
376
377 static void
378 _image_loaded_cb(void *data, const void *msg_received)
379 {
380    const Msg_Base *answer = msg_received;
381    const Msg_Loaded *msg = msg_received;
382    Image_Entry *ie = data;
383
384    ie->load_rid = 0;
385
386    if (!ie->data2)
387      return;
388
389    if (answer->type == CSERVE2_ERROR)
390      {
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);
394         free(ie->data2);
395         ie->data2 = NULL;
396         return;
397      }
398
399    _loaded_handle(ie, msg);
400 }
401
402 static void
403 _image_preloaded_cb(void *data, const void *msg_received)
404 {
405    const Msg_Base *answer = msg_received;
406    Image_Entry *ie = data;
407    Data_Entry *dentry = ie->data2;
408
409    DBG("Received PRELOADED for RID: %d", answer->rid);
410    ie->preload_rid = 0;
411
412    if (answer->type == CSERVE2_ERROR)
413      {
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;
419         return;
420      }
421
422    _loaded_handle(ie, msg_received);
423
424    if (dentry && (dentry->preloaded_cb))
425      {
426         dentry->preloaded_cb(data, EINA_TRUE);
427         dentry->preloaded_cb = NULL;
428      }
429 }
430
431 static const char *
432 _build_absolute_path(const char *path, char buf[], int size)
433 {
434    char *p;
435    int len;
436
437    if (!path)
438      return NULL;
439
440    p = buf;
441
442    if (path[0] == '/')
443      strncpy(p, path, size);
444    else if (path[0] == '~')
445      {
446         const char *home = getenv("HOME");
447         if (!home)
448           return NULL;
449         strncpy(p, home, size);
450         len = strlen(p);
451         size -= len + 1;
452         p += len;
453         p[0] = '/';
454         p++;
455         strncpy(p, path + 2, size);
456      }
457    else
458      {
459         if (!getcwd(p, size))
460           return NULL;
461         len = strlen(p);
462         size -= len + 1;
463         p += len;
464         p[0] = '/';
465         p++;
466         strncpy(p, path, size);
467      }
468
469    return buf;
470 }
471
472 static unsigned int
473 _image_open_server_send(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt __UNUSED__)
474 {
475    int flen, klen;
476    int size;
477    char *buf;
478    char filebuf[PATH_MAX];
479    Msg_Open msg_open;
480    File_Entry *fentry;
481
482    if (cserve2_init == 0)
483      {
484         ERR("Server not initialized.");
485         return 0;
486      }
487
488    if (!key) key = "";
489
490    _build_absolute_path(file, filebuf, sizeof(filebuf));
491
492    fentry = calloc(1, sizeof(*fentry));
493
494    memset(&msg_open, 0, sizeof(msg_open));
495
496    fentry->file_id = ++_file_id;
497    if (fentry->file_id == 0)
498      fentry->file_id = ++_file_id;
499
500    flen = strlen(filebuf) + 1;
501    klen = strlen(key) + 1;
502
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;
508
509    size = sizeof(msg_open) + flen + klen;
510    buf = malloc(size);
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);
515
516    if (!_server_send(buf, size, _image_opened_cb, ie))
517      {
518         ERR("Couldn't send message to server.");
519         free(buf);
520         return 0;
521      }
522
523    free(buf);
524    ie->data1 = fentry;
525
526    return msg_open.base.rid;
527 }
528
529 unsigned int
530 _image_setopts_server_send(Image_Entry *ie)
531 {
532    File_Entry *fentry;
533    Data_Entry *dentry;
534    Msg_Setopts msg;
535
536    if (cserve2_init == 0)
537      return 0;
538
539    fentry = ie->data1;
540
541    dentry = calloc(1, sizeof(*dentry));
542
543    memset(&msg, 0, sizeof(msg));
544    dentry->image_id = ++_data_id;
545    if (dentry->image_id == 0)
546      dentry->image_id = ++_data_id;
547
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;
552
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;
562
563    if (!_server_send(&msg, sizeof(msg), 0, NULL))
564      return 0;
565
566    ie->data2 = dentry;
567
568    return msg.base.rid;
569 }
570
571 unsigned int
572 _image_load_server_send(Image_Entry *ie)
573 {
574    Data_Entry *dentry;
575    Msg_Load msg;
576
577    if (cserve2_init == 0)
578      return 0;
579
580    if (!ie->data1)
581      {
582         ERR("No data for opened file.");
583         return 0;
584      }
585
586    dentry = ie->data2;
587
588    memset(&msg, 0, sizeof(msg));
589
590    msg.base.rid = _next_rid();
591    msg.base.type = CSERVE2_LOAD;
592    msg.image_id = dentry->image_id;
593
594    if (!_server_send(&msg, sizeof(msg), _image_loaded_cb, ie))
595      return 0;
596
597    return msg.base.rid;
598 }
599
600 unsigned int
601 _image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
602 {
603    Data_Entry *dentry;
604    Msg_Preload msg;
605
606    if (cserve2_init == 0)
607      return 0;
608
609    dentry = ie->data2;
610    dentry->preloaded_cb = preloaded_cb;
611
612    memset(&msg, 0, sizeof(msg));
613
614    msg.base.rid = _next_rid();
615    msg.base.type = CSERVE2_PRELOAD;
616    msg.image_id = dentry->image_id;
617
618    if (!_server_send(&msg, sizeof(msg), _image_preloaded_cb, ie))
619      return 0;
620
621    return msg.base.rid;
622 }
623
624 unsigned int
625 _image_close_server_send(Image_Entry *ie)
626 {
627    Msg_Close msg;
628    File_Entry *fentry;
629
630    if (cserve2_init == 0)
631      return 0;
632
633    if (!ie->data1)
634      return 0;
635
636    fentry = ie->data1;
637
638    if (ie->data2)
639      {
640         Data_Entry *dentry = ie->data2;
641         if (dentry->shm.data)
642           eina_file_map_free(dentry->shm.f, dentry->shm.data);
643         if (dentry->shm.f)
644           eina_file_close(dentry->shm.f);
645         free(ie->data2);
646         ie->data2 = NULL;
647      }
648
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;
653
654    free(fentry);
655    ie->data1 = NULL;
656
657    if (!_server_send(&msg, sizeof(msg), NULL, NULL))
658      return 0;
659
660    return msg.base.rid;
661 }
662
663 unsigned int
664 _image_unload_server_send(Image_Entry *ie)
665 {
666    Msg_Unload msg;
667    Data_Entry *dentry;
668
669    if (cserve2_init == 0)
670      return 0;
671
672    if (!ie->data2)
673      return 0;
674
675    dentry = ie->data2;
676
677    if (dentry->shm.data)
678      eina_file_map_free(dentry->shm.f, dentry->shm.data);
679    if (dentry->shm.f)
680      eina_file_close(dentry->shm.f);
681
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;
688
689    free(dentry);
690    ie->data2 = NULL;
691
692    if (!_server_send(&msg, sizeof(msg), NULL, NULL))
693      return 0;
694
695    return msg.base.rid;
696 }
697
698 Eina_Bool
699 evas_cserve2_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
700 {
701    unsigned int rid;
702
703    rid = _image_open_server_send(ie, file, key, lopt);
704    if (!rid)
705      return EINA_FALSE;
706
707    ie->open_rid = rid;
708
709    _image_setopts_server_send(ie);
710
711    // _server_dispatch_until(rid);
712
713    if (ie->data1)
714      return EINA_TRUE;
715    else
716      return EINA_FALSE;
717 }
718
719 int
720 evas_cserve2_image_load_wait(Image_Entry *ie)
721 {
722    if (ie->open_rid)
723      {
724         _server_dispatch_until(ie->open_rid);
725         if (!ie->data1)
726           return CSERVE2_GENERIC;
727         return CSERVE2_NONE;
728      }
729    else
730      return CSERVE2_GENERIC;
731 }
732
733 Eina_Bool
734 evas_cserve2_image_data_load(Image_Entry *ie)
735 {
736    unsigned int rid;
737
738    rid = _image_load_server_send(ie);
739    if (!rid)
740      return EINA_FALSE;
741
742    ie->load_rid = rid;
743
744    if (ie->data2)
745      return EINA_TRUE;
746    else
747      return EINA_FALSE;
748 }
749
750 void
751 evas_cserve2_image_load_data_wait(Image_Entry *ie)
752 {
753    if (ie->load_rid)
754      _server_dispatch_until(ie->load_rid);
755 }
756
757 Eina_Bool
758 evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
759 {
760    unsigned int rid;
761
762    if (!ie->data1)
763      return EINA_FALSE;
764
765    rid = _image_preload_server_send(ie, preloaded_cb);
766    if (!rid)
767      return EINA_FALSE;
768
769    ie->preload_rid = rid;
770
771    return EINA_FALSE;
772 }
773
774 void
775 evas_cserve2_image_free(Image_Entry *ie)
776 {
777    if (!ie->data1)
778      return;
779
780    if (!_image_close_server_send(ie))
781      WRN("Couldn't send close message to cserve2.");
782 }
783
784 void
785 evas_cserve2_image_unload(Image_Entry *ie)
786 {
787    if (!ie->data2)
788      return;
789
790    if (!_image_unload_server_send(ie))
791      WRN("Couldn't send unload message to cserve2.");
792 }
793
794 void
795 evas_cserve2_dispatch(void)
796 {
797    _server_dispatch_until(0);
798 }
799
800 typedef struct _Glyph_Map Glyph_Map;
801 typedef struct _CS_Glyph_Out CS_Glyph_Out;
802
803 struct _Font_Entry
804 {
805    const char *source;
806    const char *name;
807    unsigned int size;
808    unsigned int dpi;
809    Font_Rend_Flags wanted_rend;
810
811    unsigned int rid; // open
812
813    Eina_Hash *glyphs_maps;
814    Fash_Glyph2 *fash[3]; // one per hinting value
815
816    Eina_Clist glyphs_queue;
817    int glyphs_queue_count;
818    Eina_Clist glyphs_used;
819    int glyphs_used_count;
820
821    Eina_Bool failed : 1;
822 };
823
824 struct _Glyph_Map
825 {
826    Font_Entry *fe;
827    const char *name;
828    unsigned int size;
829    Eina_File *map;
830    unsigned char *data;
831    Eina_Clist glyphs;
832 };
833
834 struct _CS_Glyph_Out
835 {
836    RGBA_Font_Glyph_Out base;
837    Eina_Clist map_entry;
838    Eina_Clist used_list;
839    unsigned int idx;
840    unsigned int rid;
841    Glyph_Map *map;
842    unsigned int offset;
843    unsigned int size;
844    Eina_Bool used;
845 };
846
847 static void
848 _font_entry_free(Font_Entry *fe)
849 {
850    int i;
851
852    for (i = 0; i < 3; i++)
853      if (fe->fash[i])
854        fash_gl_free(fe->fash[i]);
855
856    eina_stringshare_del(fe->source);
857    eina_stringshare_del(fe->name);
858    eina_hash_free(fe->glyphs_maps);
859    free(fe);
860 }
861
862 static void
863 _glyphs_map_free(Glyph_Map *m)
864 {
865    eina_file_map_free(m->map, m->data);
866    eina_file_close(m->map);
867    eina_stringshare_del(m->name);
868    free(m);
869 }
870
871 static void
872 _glyph_out_free(void *gl)
873 {
874    CS_Glyph_Out *glout = gl;
875
876    if (glout->map)
877      {
878         eina_clist_remove(&glout->map_entry);
879         if (eina_clist_empty(&glout->map->glyphs))
880           {
881              eina_hash_del(glout->map->fe->glyphs_maps, &glout->map->name,
882                            NULL);
883              _glyphs_map_free(glout->map);
884           }
885      }
886
887    free(glout);
888 }
889
890 static void
891 _font_loaded_cb(void *data, const void *msg)
892 {
893    const Msg_Base *m = msg;
894    Font_Entry *fe = data;
895
896    fe->rid = 0;
897
898    if (m->type == CSERVE2_ERROR)
899      fe->failed = EINA_TRUE;
900 }
901
902 static unsigned int
903 _font_load_server_send(Font_Entry *fe, Message_Type type)
904 {
905    Msg_Font_Load *msg;
906    int source_len, path_len, size;
907    char *buf;
908    unsigned int ret = 0;
909    void (*cb)(void *data, const void *msg) = NULL;
910
911    if (!cserve2_init)
912      return 0;
913
914    source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
915    path_len = eina_stringshare_strlen(fe->name) + 1;
916
917    size = sizeof(*msg) + path_len + source_len;
918    msg = calloc(1, size);
919
920    msg->base.rid = _next_rid();
921    msg->base.type = type;
922
923    msg->sourcelen = source_len;
924    msg->pathlen = path_len;
925    msg->rend_flags = fe->wanted_rend;
926    msg->size = fe->size;
927    msg->dpi = fe->dpi;
928
929    buf = ((char *)msg) + sizeof(*msg);
930    memcpy(buf, fe->source, source_len);
931    buf += source_len;
932    memcpy(buf, fe->name, path_len);
933
934    if (type == CSERVE2_FONT_LOAD)
935      cb = _font_loaded_cb;
936
937    if (_server_send(msg, size, cb, fe))
938      ret = msg->base.rid;
939
940    free(msg);
941
942    return ret;
943 }
944
945 Font_Entry *
946 evas_cserve2_font_load(const char *source, const char *name, int size, int dpi, Font_Rend_Flags wanted_rend)
947 {
948    Font_Entry *fe;
949
950    fe = calloc(1, sizeof(Font_Entry));
951    if (!fe) return NULL;
952
953    fe->source = source ? eina_stringshare_add(source) : NULL;
954    fe->name = eina_stringshare_add(name);
955    fe->size = size;
956    fe->dpi = dpi;
957    fe->wanted_rend = wanted_rend;
958
959    if (!(fe->rid = _font_load_server_send(fe, CSERVE2_FONT_LOAD)))
960      {
961         eina_stringshare_del(fe->source);
962         eina_stringshare_del(fe->name);
963         free(fe);
964         return NULL;
965      }
966
967    fe->glyphs_maps = eina_hash_stringshared_new(NULL);
968    eina_clist_init(&fe->glyphs_queue);
969    eina_clist_init(&fe->glyphs_used);
970
971    return fe;
972 }
973
974 void
975 evas_cserve2_font_free(Font_Entry *fe)
976 {
977    if (!fe) return;
978
979    if (fe->failed)
980      return;
981
982    _font_load_server_send(fe, CSERVE2_FONT_UNLOAD);
983
984    _font_entry_free(fe);
985 }
986
987 typedef struct
988 {
989    Font_Entry *fe;
990    Font_Hint_Flags hints;
991    unsigned int rid;
992 } Glyph_Request_Data;
993
994 static void
995 _glyph_request_cb(void *data, const void *msg)
996 {
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;
1001    const char *buf;
1002
1003    if (resp->base.type == CSERVE2_ERROR)
1004      {
1005         free(grd);
1006         return;
1007      }
1008
1009    buf = (const char *)resp + sizeof(*resp);
1010    while (ncaches < resp->ncaches)
1011      {
1012         int i = 0, nglyphs;
1013         int namelen;
1014         const char *name;
1015         Glyph_Map *map;
1016
1017         memcpy(&namelen, buf, sizeof(int));
1018         buf += sizeof(int);
1019
1020         name = eina_stringshare_add_length(buf, namelen);
1021         buf += namelen;
1022
1023         memcpy(&nglyphs, buf, sizeof(int));
1024         buf += sizeof(int);
1025
1026         map = eina_hash_find(fe->glyphs_maps, name);
1027         if (!map)
1028           {
1029              map = calloc(1, sizeof(*map));
1030              map->fe = fe;
1031              map->name = name;
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);
1036           }
1037         else
1038           eina_stringshare_del(name);
1039
1040         while (i < nglyphs)
1041           {
1042              unsigned int idx, offset, glsize;
1043              int rows, width, pitch, num_grays, pixel_mode;
1044              CS_Glyph_Out *gl;
1045
1046              memcpy(&idx, buf, sizeof(int));
1047              buf += sizeof(int);
1048              memcpy(&offset, buf, sizeof(int));
1049              buf += sizeof(int);
1050              memcpy(&glsize, buf, sizeof(int));
1051              buf += sizeof(int);
1052              memcpy(&rows, buf, sizeof(int));
1053              buf += sizeof(int);
1054              memcpy(&width, buf, sizeof(int));
1055              buf += sizeof(int);
1056              memcpy(&pitch, buf, sizeof(int));
1057              buf += sizeof(int);
1058              memcpy(&num_grays, buf, sizeof(int));
1059              buf += sizeof(int);
1060              memcpy(&pixel_mode, buf, sizeof(int));
1061              buf += sizeof(int);
1062
1063              gl = fash_gl_find(fe->fash[grd->hints], idx);
1064              gl->map = map;
1065              gl->offset = offset;
1066              gl->size = glsize;
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;
1073
1074              gl->rid = 0;
1075
1076              eina_clist_add_head(&map->glyphs, &gl->map_entry);
1077
1078              i++;
1079           }
1080
1081         ncaches++;
1082      }
1083
1084    free(grd);
1085 }
1086
1087 static unsigned int
1088 _glyph_request_server_send(Font_Entry *fe, Font_Hint_Flags hints, Eina_Bool used)
1089 {
1090    Msg_Font_Glyphs_Request *msg;
1091    Glyph_Request_Data *grd = NULL;
1092    int source_len, name_len, size, nglyphs;
1093    char *buf;
1094    unsigned int *glyphs;
1095    unsigned int ret = 0;
1096    Op_Callback cb;
1097    Eina_Clist *queue, *itr, *itr_next;
1098
1099
1100    source_len = fe->source ? eina_stringshare_strlen(fe->source) + 1 : 0;
1101    name_len = eina_stringshare_strlen(fe->name) + 1;
1102
1103    if (!used)
1104      {
1105         nglyphs = fe->glyphs_queue_count;
1106         queue = &fe->glyphs_queue;
1107      }
1108    else
1109      {
1110         nglyphs = fe->glyphs_used_count;
1111         queue = &fe->glyphs_used;
1112      }
1113
1114    size = sizeof(*msg) + source_len + name_len + (nglyphs * sizeof(int));
1115    msg = calloc(1, size);
1116
1117    msg->base.rid = _next_rid();
1118    if (!used)
1119      msg->base.type = CSERVE2_FONT_GLYPHS_LOAD;
1120    else
1121      msg->base.type = CSERVE2_FONT_GLYPHS_USED;
1122
1123    msg->sourcelen = source_len;
1124    msg->pathlen = name_len;
1125    msg->rend_flags = fe->wanted_rend;
1126    msg->size = fe->size;
1127    msg->dpi = fe->dpi;
1128    msg->hint = hints;
1129    msg->nglyphs = nglyphs;
1130
1131    buf = ((char *)msg) + sizeof(*msg);
1132    memcpy(buf, fe->source, source_len);
1133    buf += source_len;
1134    memcpy(buf, fe->name, name_len);
1135    buf += name_len;
1136    glyphs = (unsigned int *)buf;
1137    nglyphs = 0;
1138    EINA_CLIST_FOR_EACH_SAFE(itr, itr_next, queue)
1139      {
1140         CS_Glyph_Out *gl;
1141
1142         if (!used)
1143           {
1144              gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, map_entry);
1145              gl->rid = msg->base.rid;
1146              eina_clist_remove(&gl->map_entry);
1147           }
1148         else
1149           {
1150              gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, used_list);
1151              gl->used = EINA_FALSE;
1152              eina_clist_remove(&gl->used_list);
1153           }
1154         glyphs[nglyphs++] = gl->idx;
1155      }
1156    if (!used)
1157      fe->glyphs_queue_count = 0;
1158    else
1159      fe->glyphs_used_count = 0;
1160
1161    if (!used)
1162      {
1163         cb = _glyph_request_cb;
1164         grd = malloc(sizeof(*grd));
1165         grd->fe = fe;
1166         grd->rid = msg->base.rid;
1167         grd->hints = hints;
1168      }
1169    else
1170      cb = NULL;
1171
1172    if (_server_send(msg, size, cb, grd))
1173      ret = msg->base.rid;
1174    else
1175      free(grd);
1176
1177    free(msg);
1178
1179    return ret;
1180 }
1181
1182 Eina_Bool
1183 evas_cserve2_font_glyph_request(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1184 {
1185    Fash_Glyph2 *fash;
1186    CS_Glyph_Out *glyph;
1187
1188    if (fe->rid)
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 */
1192
1193    if (fe->failed)
1194      return EINA_FALSE;
1195
1196    fash = fe->fash[hints];
1197    if (!fash)
1198      {
1199         fash = fash_gl_new(_glyph_out_free);
1200         fe->fash[hints] = fash;
1201      }
1202
1203    glyph = fash_gl_find(fash, idx);
1204    if (!glyph)
1205      {
1206         glyph = calloc(1, sizeof(*glyph));
1207
1208         glyph->idx = idx;
1209
1210         fash_gl_add(fash, idx, glyph);
1211
1212         eina_clist_add_head(&fe->glyphs_queue, &glyph->map_entry);
1213         fe->glyphs_queue_count++;
1214      }
1215    else if (!glyph->used)
1216      {
1217         eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1218         fe->glyphs_used_count++;
1219         glyph->used = EINA_TRUE;
1220      }
1221
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);
1225
1226    return EINA_TRUE;
1227 }
1228
1229 Eina_Bool
1230 evas_cserve2_font_glyph_used(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1231 {
1232    Fash_Glyph2 *fash;
1233    CS_Glyph_Out *glyph;
1234
1235    if (fe->rid)
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 */
1239
1240    if (fe->failed)
1241      return EINA_FALSE;
1242
1243    fash = fe->fash[hints];
1244    if (!fash)
1245      return EINA_FALSE;
1246
1247    glyph = fash_gl_find(fash, idx);
1248    /* If we found the glyph on client cache, we should also have at least
1249     * its request done.
1250     */
1251    if (!glyph)
1252      return EINA_FALSE;
1253
1254    if (!glyph->map)
1255      return EINA_TRUE;
1256
1257    if (glyph->used)
1258      return EINA_TRUE;
1259
1260    eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1261    fe->glyphs_used_count++;
1262    glyph->used = EINA_TRUE;
1263
1264    return EINA_TRUE;
1265 }
1266
1267 RGBA_Font_Glyph_Out *
1268 evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints)
1269 {
1270    Fash_Glyph2 *fash;
1271    CS_Glyph_Out *out;
1272
1273    if (fe->failed)
1274      return NULL;
1275
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);
1279
1280    if (fe->glyphs_used_count)
1281      _glyph_request_server_send(fe, hints, EINA_TRUE);
1282
1283    fash = fe->fash[hints];
1284    if (!fash)
1285      {
1286         // this should not happen really, so let the user know he fucked up
1287         system("format c:");
1288         return NULL;
1289      }
1290
1291    out = fash_gl_find(fash, idx);
1292    if (!out)
1293      {
1294         // again, if we are asking for a bitmap we were supposed to already
1295         // have requested the glyph, it must be there
1296         return NULL;
1297      }
1298    if (out->rid)
1299      _server_dispatch_until(out->rid);
1300
1301    // promote shm and font entry in lru or something
1302
1303    return &(out->base);
1304 }
1305
1306 #endif