summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2013-10-28 15:50:57 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2013-10-28 15:51:10 +0900
commit7338164468370056e35c206a47ca3fe1b1b61f38 (patch)
tree42603e5b79eb86c8b8154f0b4de8d24107ea9b26 /src/lib
parent9f690ba390fe0922df10cdefe07db8680d5a088f (diff)
parent15130078156d849f942fb00c4f37bd708bad0c7b (diff)
Evas/cserve2: Merge branch 'devs/jpeg/cserve2'
Improve stability, performance and overall support of evas cserve2. In particular: - Implement shared indexes and memory pools to share cserve's internal state with all clients. Apps can then scan these indexes and avoid waiting for socket responses when loading resources. - Implement crash resiliency in evas. If cserve2 crashes, apps can safely reconnect and continue working as if nothing happened. - Implement support for the GL engine (very basic support so far, "just works"). - Improve performance by reusing the scalecache logic.
Diffstat (limited to '')
-rw-r--r--src/lib/evas/cache2/evas_cache2.c179
-rw-r--r--src/lib/evas/cache2/evas_cache2.h2
-rw-r--r--src/lib/evas/canvas/evas_main.c11
-rw-r--r--src/lib/evas/canvas/evas_object_image.c56
-rw-r--r--src/lib/evas/canvas/evas_object_inform.c2
-rw-r--r--src/lib/evas/canvas/evas_render.c2
-rw-r--r--src/lib/evas/common/evas_font_draw.c53
-rw-r--r--src/lib/evas/common/evas_font_main.c13
-rw-r--r--src/lib/evas/common/evas_image_load.c35
-rw-r--r--src/lib/evas/common/evas_image_scalecache.c22
-rw-r--r--src/lib/evas/cserve2/evas_cs2.h158
-rw-r--r--src/lib/evas/cserve2/evas_cs2_client.c2048
-rw-r--r--src/lib/evas/cserve2/evas_cs2_image_data.c9
-rw-r--r--src/lib/evas/cserve2/evas_cs2_private.h59
-rw-r--r--src/lib/evas/cserve2/evas_cs2_utils.c2
15 files changed, 2247 insertions, 404 deletions
diff --git a/src/lib/evas/cache2/evas_cache2.c b/src/lib/evas/cache2/evas_cache2.c
index 81fd78c8d8..e1a9d01120 100644
--- a/src/lib/evas/cache2/evas_cache2.c
+++ b/src/lib/evas/cache2/evas_cache2.c
@@ -33,23 +33,23 @@
33// Default LRU size. If 0, all scaled images will be dropped instantly. 33// Default LRU size. If 0, all scaled images will be dropped instantly.
34#define DEFAULT_CACHE_LRU_SIZE (4*1024*1024) 34#define DEFAULT_CACHE_LRU_SIZE (4*1024*1024)
35 35
36static void _evas_cache_image_dirty_add(Image_Entry *im); 36static void _evas_cache2_image_dirty_add(Image_Entry *im);
37static void _evas_cache_image_dirty_del(Image_Entry *im); 37static void _evas_cache2_image_dirty_del(Image_Entry *im);
38static void _evas_cache_image_activ_add(Image_Entry *im); 38static void _evas_cache2_image_activ_add(Image_Entry *im);
39static void _evas_cache_image_activ_del(Image_Entry *im); 39static void _evas_cache2_image_activ_del(Image_Entry *im);
40static void _evas_cache_image_lru_add(Image_Entry *im); 40static void _evas_cache2_image_lru_add(Image_Entry *im);
41static void _evas_cache_image_lru_del(Image_Entry *im); 41static void _evas_cache2_image_lru_del(Image_Entry *im);
42static void _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target); 42static void _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target);
43// static void _evas_cache_image_lru_nodata_add(Image_Entry *im); 43// static void _evas_cache2_image_lru_nodata_add(Image_Entry *im);
44// static void _evas_cache_image_lru_nodata_del(Image_Entry *im); 44// static void _evas_cache2_image_lru_nodata_del(Image_Entry *im);
45 45
46static void 46static void
47_evas_cache_image_dirty_add(Image_Entry *im) 47_evas_cache2_image_dirty_add(Image_Entry *im)
48{ 48{
49 if (im->flags.dirty) return; 49 if (im->flags.dirty) return;
50 _evas_cache_image_activ_del(im); 50 _evas_cache2_image_activ_del(im);
51 _evas_cache_image_lru_del(im); 51 _evas_cache2_image_lru_del(im);
52 // _evas_cache_image_lru_nodata_del(im); 52 // _evas_cache2_image_lru_nodata_del(im);
53 im->flags.dirty = 1; 53 im->flags.dirty = 1;
54 im->flags.cached = 1; 54 im->flags.cached = 1;
55 im->cache2->dirty = eina_inlist_prepend(im->cache2->dirty, EINA_INLIST_GET(im)); 55 im->cache2->dirty = eina_inlist_prepend(im->cache2->dirty, EINA_INLIST_GET(im));
@@ -61,7 +61,7 @@ _evas_cache_image_dirty_add(Image_Entry *im)
61} 61}
62 62
63static void 63static void
64_evas_cache_image_dirty_del(Image_Entry *im) 64_evas_cache2_image_dirty_del(Image_Entry *im)
65{ 65{
66 if (!im->flags.dirty) return; 66 if (!im->flags.dirty) return;
67 if (!im->cache2) return; 67 if (!im->cache2) return;
@@ -71,12 +71,12 @@ _evas_cache_image_dirty_del(Image_Entry *im)
71} 71}
72 72
73static void 73static void
74_evas_cache_image_activ_add(Image_Entry *im) 74_evas_cache2_image_activ_add(Image_Entry *im)
75{ 75{
76 if (im->flags.activ) return; 76 if (im->flags.activ) return;
77 _evas_cache_image_dirty_del(im); 77 _evas_cache2_image_dirty_del(im);
78 _evas_cache_image_lru_del(im); 78 _evas_cache2_image_lru_del(im);
79 // _evas_cache_image_lru_nodata_del(im); 79 // _evas_cache2_image_lru_nodata_del(im);
80 if (!im->cache_key) return; 80 if (!im->cache_key) return;
81 im->flags.activ = 1; 81 im->flags.activ = 1;
82 im->flags.cached = 1; 82 im->flags.cached = 1;
@@ -84,7 +84,7 @@ _evas_cache_image_activ_add(Image_Entry *im)
84} 84}
85 85
86static void 86static void
87_evas_cache_image_activ_del(Image_Entry *im) 87_evas_cache2_image_activ_del(Image_Entry *im)
88{ 88{
89 if (!im->flags.activ) return; 89 if (!im->flags.activ) return;
90 if (!im->cache_key) return; 90 if (!im->cache_key) return;
@@ -94,12 +94,12 @@ _evas_cache_image_activ_del(Image_Entry *im)
94} 94}
95 95
96static void 96static void
97_evas_cache_image_lru_add(Image_Entry *im) 97_evas_cache2_image_lru_add(Image_Entry *im)
98{ 98{
99 if (im->flags.lru) return; 99 if (im->flags.lru) return;
100 _evas_cache_image_dirty_del(im); 100 _evas_cache2_image_dirty_del(im);
101 _evas_cache_image_activ_del(im); 101 _evas_cache2_image_activ_del(im);
102 // _evas_cache_image_lru_nodata_del(im); 102 // _evas_cache2_image_lru_nodata_del(im);
103 if (!im->cache_key) return; 103 if (!im->cache_key) return;
104 im->flags.lru = 1; 104 im->flags.lru = 1;
105 im->flags.cached = 1; 105 im->flags.cached = 1;
@@ -109,7 +109,7 @@ _evas_cache_image_lru_add(Image_Entry *im)
109} 109}
110 110
111static void 111static void
112_evas_cache_image_lru_del(Image_Entry *im) 112_evas_cache2_image_lru_del(Image_Entry *im)
113{ 113{
114 if (!im->flags.lru) return; 114 if (!im->flags.lru) return;
115 if (!im->cache_key) return; 115 if (!im->cache_key) return;
@@ -122,19 +122,19 @@ _evas_cache_image_lru_del(Image_Entry *im)
122 122
123/* 123/*
124static void 124static void
125_evas_cache_image_lru_nodata_add(Image_Entry *im) 125_evas_cache2_image_lru_nodata_add(Image_Entry *im)
126{ 126{
127 if (im->flags.lru_nodata) return; 127 if (im->flags.lru_nodata) return;
128 _evas_cache_image_dirty_del(im); 128 _evas_cache2_image_dirty_del(im);
129 _evas_cache_image_activ_del(im); 129 _evas_cache2_image_activ_del(im);
130 _evas_cache_image_lru_del(im); 130 _evas_cache2_image_lru_del(im);
131 im->flags.lru = 1; 131 im->flags.lru = 1;
132 im->flags.cached = 1; 132 im->flags.cached = 1;
133 im->cache2->lru_nodata = eina_inlist_prepend(im->cache2->lru_nodata, EINA_INLIST_GET(im)); 133 im->cache2->lru_nodata = eina_inlist_prepend(im->cache2->lru_nodata, EINA_INLIST_GET(im));
134} 134}
135 135
136static void 136static void
137_evas_cache_image_lru_nodata_del(Image_Entry *im) 137_evas_cache2_image_lru_nodata_del(Image_Entry *im)
138{ 138{
139 if (!im->flags.lru_nodata) return; 139 if (!im->flags.lru_nodata) return;
140 im->flags.lru = 0; 140 im->flags.lru = 0;
@@ -177,7 +177,7 @@ _timestamp_build(Image_Timestamp *tstamp, struct stat *st)
177} 177}
178 178
179static void 179static void
180_evas_cache_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie) 180_evas_cache2_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie)
181{ 181{
182 if (!ie) return; 182 if (!ie) return;
183 183
@@ -191,10 +191,10 @@ _evas_cache_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie)
191 return; 191 return;
192 } 192 }
193 193
194 _evas_cache_image_dirty_del(ie); 194 _evas_cache2_image_dirty_del(ie);
195 _evas_cache_image_activ_del(ie); 195 _evas_cache2_image_activ_del(ie);
196 _evas_cache_image_lru_del(ie); 196 _evas_cache2_image_lru_del(ie);
197 // _evas_cache_image_lru_nodata_del(ie); 197 // _evas_cache2_image_lru_nodata_del(ie);
198 198
199 199
200 if (ie->data1) 200 if (ie->data1)
@@ -220,7 +220,7 @@ _evas_cache_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie)
220} 220}
221 221
222static Image_Entry * 222static Image_Entry *
223_evas_cache_image_entry_new(Evas_Cache2 *cache, 223_evas_cache2_image_entry_new(Evas_Cache2 *cache,
224 const char *hkey, 224 const char *hkey,
225 Image_Timestamp *tstamp, 225 Image_Timestamp *tstamp,
226 const char *file, 226 const char *file,
@@ -264,15 +264,15 @@ _evas_cache_image_entry_new(Evas_Cache2 *cache,
264 { 264 {
265 ERR("couldn't load '%s' '%s' with cserve2!", 265 ERR("couldn't load '%s' '%s' with cserve2!",
266 ie->file, ie->key ? ie->key : ""); 266 ie->file, ie->key ? ie->key : "");
267 _evas_cache_image_entry_delete(cache, ie); 267 _evas_cache2_image_entry_delete(cache, ie);
268 if (error) 268 if (error)
269 *error = EVAS_LOAD_ERROR_GENERIC; 269 *error = EVAS_LOAD_ERROR_GENERIC;
270 return NULL; 270 return NULL;
271 } 271 }
272 } 272 }
273 273
274 if (ie->cache_key) _evas_cache_image_activ_add(ie); 274 if (ie->cache_key) _evas_cache2_image_activ_add(ie);
275 else _evas_cache_image_dirty_add(ie); 275 else _evas_cache2_image_dirty_add(ie);
276 276
277 if (error) 277 if (error)
278 *error = EVAS_LOAD_ERROR_NONE; 278 *error = EVAS_LOAD_ERROR_NONE;
@@ -319,7 +319,7 @@ _evas_cache2_image_preloaded_cb(void *data, Eina_Bool success)
319 } 319 }
320 320
321 if (ie->flags.delete_me) 321 if (ie->flags.delete_me)
322 _evas_cache_image_entry_delete(ie->cache2, ie); 322 _evas_cache2_image_entry_delete(ie->cache2, ie);
323} 323}
324 324
325static Eina_Bool 325static Eina_Bool
@@ -393,7 +393,7 @@ evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h
393 (cspace == EVAS_COLORSPACE_YCBCR422601_PL)) 393 (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
394 w &= ~0x1; 394 w &= ~0x1;
395 395
396 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL); 396 im = _evas_cache2_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
397 if (!im) 397 if (!im)
398 return NULL; 398 return NULL;
399 399
@@ -402,7 +402,7 @@ evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h
402 evas_cache2_image_surface_alloc(im, w, h); 402 evas_cache2_image_surface_alloc(im, w, h);
403 if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0) 403 if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
404 { 404 {
405 _evas_cache_image_entry_delete(cache, im); 405 _evas_cache2_image_entry_delete(cache, im);
406 return NULL; 406 return NULL;
407 } 407 }
408 408
@@ -423,14 +423,14 @@ evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA3
423 (cspace == EVAS_COLORSPACE_YCBCR422601_PL)) 423 (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
424 w &= ~0x1; 424 w &= ~0x1;
425 425
426 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL); 426 im = _evas_cache2_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
427 if (!im) return NULL; 427 if (!im) return NULL;
428 im->w = w; 428 im->w = w;
429 im->h = h; 429 im->h = h;
430 im->flags.alpha = alpha; 430 im->flags.alpha = alpha;
431 if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0) 431 if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
432 { 432 {
433 _evas_cache_image_entry_delete(cache, im); 433 _evas_cache2_image_entry_delete(cache, im);
434 return NULL; 434 return NULL;
435 } 435 }
436 im->references = 1; 436 im->references = 1;
@@ -444,7 +444,7 @@ evas_cache2_image_empty(Evas_Cache2 *cache)
444{ 444{
445 Image_Entry *im; 445 Image_Entry *im;
446 446
447 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL); 447 im = _evas_cache2_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
448 if (!im) 448 if (!im)
449 return NULL; 449 return NULL;
450 450
@@ -467,7 +467,7 @@ evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h)
467 if ((im->w == w) && (im->h == h)) return im; 467 if ((im->w == w) && (im->h == h)) return im;
468 468
469 cache = im->cache2; 469 cache = im->cache2;
470 im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, 470 im2 = _evas_cache2_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL,
471 NULL); 471 NULL);
472 if (!im2) goto on_error; 472 if (!im2) goto on_error;
473 473
@@ -486,7 +486,7 @@ evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h)
486 486
487on_error: 487on_error:
488 if (im2) 488 if (im2)
489 _evas_cache_image_entry_delete(cache, im2); 489 _evas_cache2_image_entry_delete(cache, im2);
490 return NULL; 490 return NULL;
491} 491}
492 492
@@ -510,7 +510,7 @@ evas_cache2_init(const Evas_Cache2_Image_Func *cb)
510} 510}
511 511
512static Eina_Bool 512static Eina_Bool
513_evas_cache_image_free_cb(EINA_UNUSED const Eina_Hash *hash, EINA_UNUSED const void *key, void *data, void *fdata) 513_evas_cache2_image_free_cb(EINA_UNUSED const Eina_Hash *hash, EINA_UNUSED const void *key, void *data, void *fdata)
514{ 514{
515 Eina_List **delete_list = fdata; 515 Eina_List **delete_list = fdata;
516 *delete_list = eina_list_prepend(*delete_list, data); 516 *delete_list = eina_list_prepend(*delete_list, data);
@@ -526,20 +526,20 @@ evas_cache2_shutdown(Evas_Cache2 *cache)
526 while (cache->lru) 526 while (cache->lru)
527 { 527 {
528 im = (Image_Entry *)cache->lru; 528 im = (Image_Entry *)cache->lru;
529 _evas_cache_image_entry_delete(cache, im); 529 _evas_cache2_image_entry_delete(cache, im);
530 } 530 }
531 /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */ 531 /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */
532 while (cache->dirty) 532 while (cache->dirty)
533 { 533 {
534 im = (Image_Entry *)cache->dirty; 534 im = (Image_Entry *)cache->dirty;
535 _evas_cache_image_entry_delete(cache, im); 535 _evas_cache2_image_entry_delete(cache, im);
536 } 536 }
537 537
538 delete_list = NULL; 538 delete_list = NULL;
539 eina_hash_foreach(cache->activ, _evas_cache_image_free_cb, &delete_list); 539 eina_hash_foreach(cache->activ, _evas_cache2_image_free_cb, &delete_list);
540 while (delete_list) 540 while (delete_list)
541 { 541 {
542 _evas_cache_image_entry_delete(cache, eina_list_data_get(delete_list)); 542 _evas_cache2_image_entry_delete(cache, eina_list_data_get(delete_list));
543 delete_list = eina_list_remove_list(delete_list, delete_list); 543 delete_list = eina_list_remove_list(delete_list, delete_list);
544 } 544 }
545 545
@@ -549,8 +549,17 @@ evas_cache2_shutdown(Evas_Cache2 *cache)
549 free(cache); 549 free(cache);
550} 550}
551 551
552static void 552EAPI Eina_Bool
553_create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, Evas_Image_Load_Opts *lo) 553evas_cache2_image_cached(Image_Entry *ie)
554{
555 if (!ie) return EINA_FALSE;
556 return (ie->cache2 != NULL);
557}
558
559EAPI void
560evas_cache2_image_cache_key_create(char *hkey, const char *path, size_t pathlen,
561 const char *key, size_t keylen,
562 const Evas_Image_Load_Opts *lo)
554{ 563{
555 const char *ckey = "(null)"; 564 const char *ckey = "(null)";
556 size_t size; 565 size_t size;
@@ -561,6 +570,7 @@ _create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key,
561 memcpy(hkey + size, "//://", 5); 570 memcpy(hkey + size, "//://", 5);
562 size += 5; 571 size += 5;
563 if (key) ckey = key; 572 if (key) ckey = key;
573 else keylen = 6;
564 memcpy(hkey + size, ckey, keylen); 574 memcpy(hkey + size, ckey, keylen);
565 size += keylen; 575 size += keylen;
566 if (lo) 576 if (lo)
@@ -634,7 +644,8 @@ _create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key,
634} 644}
635 645
636EAPI Image_Entry * 646EAPI Image_Entry *
637evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, Evas_Image_Load_Opts *lo, int *error) 647evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key,
648 Evas_Image_Load_Opts *lo, int *error)
638{ 649{
639 size_t size; 650 size_t size;
640 size_t pathlen; 651 size_t pathlen;
@@ -659,7 +670,7 @@ evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, Ev
659 size = pathlen + keylen + HKEY_LOAD_OPTS_STR_LEN; 670 size = pathlen + keylen + HKEY_LOAD_OPTS_STR_LEN;
660 hkey = alloca(sizeof(char) * size); 671 hkey = alloca(sizeof(char) * size);
661 672
662 _create_hash_key(hkey, path, pathlen, key, keylen, lo); 673 evas_cache2_image_cache_key_create(hkey, path, pathlen, key, keylen, lo);
663 DBG("Looking at the hash for key '%s'", hkey); 674 DBG("Looking at the hash for key '%s'", hkey);
664 675
665 /* use local var to copy default load options to the image entry */ 676 /* use local var to copy default load options to the image entry */
@@ -697,7 +708,7 @@ evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, Ev
697 * of an image at a given key. we wither find it and keep re-reffing 708 * of an image at a given key. we wither find it and keep re-reffing
698 * it or we dirty it and get it out */ 709 * it or we dirty it and get it out */
699 DBG("Entry on inactive hash was invalid (file changed or deleted)."); 710 DBG("Entry on inactive hash was invalid (file changed or deleted).");
700 _evas_cache_image_dirty_add(im); 711 _evas_cache2_image_dirty_add(im);
701 im = NULL; 712 im = NULL;
702 } 713 }
703 714
@@ -723,15 +734,15 @@ evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, Ev
723 if (ok) 734 if (ok)
724 { 735 {
725 /* remove from lru and make it active again */ 736 /* remove from lru and make it active again */
726 _evas_cache_image_lru_del(im); 737 _evas_cache2_image_lru_del(im);
727 _evas_cache_image_activ_add(im); 738 _evas_cache2_image_activ_add(im);
728 goto on_ok; 739 goto on_ok;
729 } 740 }
730 DBG("Entry on inactive hash was invalid (file changed or deleted)."); 741 DBG("Entry on inactive hash was invalid (file changed or deleted).");
731 /* as avtive cache find - if we match in lru and its invalid, dirty */ 742 /* as avtive cache find - if we match in lru and its invalid, dirty */
732 _evas_cache_image_dirty_add(im); 743 _evas_cache2_image_dirty_add(im);
733 /* this image never used, so it have to be deleted */ 744 /* this image never used, so it have to be deleted */
734 _evas_cache_image_entry_delete(cache, im); 745 _evas_cache2_image_entry_delete(cache, im);
735 im = NULL; 746 im = NULL;
736 } 747 }
737 if (stat_failed) goto on_stat_error; 748 if (stat_failed) goto on_stat_error;
@@ -742,7 +753,7 @@ evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, Ev
742 } 753 }
743 _timestamp_build(&tstamp, &st); 754 _timestamp_build(&tstamp, &st);
744 DBG("Creating a new entry for key '%s'.", hkey); 755 DBG("Creating a new entry for key '%s'.", hkey);
745 im = _evas_cache_image_entry_new(cache, hkey, &tstamp, path, key, 756 im = _evas_cache2_image_entry_new(cache, hkey, &tstamp, path, key,
746 lo, error); 757 lo, error);
747 if (!im) goto on_stat_error; 758 if (!im) goto on_stat_error;
748 759
@@ -773,7 +784,7 @@ on_stat_error:
773 else 784 else
774 *error = EVAS_LOAD_ERROR_GENERIC; 785 *error = EVAS_LOAD_ERROR_GENERIC;
775 786
776 if (im) _evas_cache_image_entry_delete(cache, im); 787 if (im) _evas_cache2_image_entry_delete(cache, im);
777 return NULL; 788 return NULL;
778} 789}
779 790
@@ -788,7 +799,8 @@ evas_cache2_image_open_wait(Image_Entry *im)
788} 799}
789 800
790static Image_Entry * 801static Image_Entry *
791_scaled_image_find(Image_Entry *im, int src_x, int src_y, int src_w, int src_h, int dst_w, int dst_h, int smooth) 802_scaled_image_find(Image_Entry *im, int src_x, int src_y, int src_w,
803 int src_h, int dst_w, int dst_h, int smooth)
792{ 804{
793 size_t pathlen, keylen, size; 805 size_t pathlen, keylen, size;
794 char *hkey; 806 char *hkey;
@@ -816,7 +828,8 @@ _scaled_image_find(Image_Entry *im, int src_x, int src_y, int src_w, int src_h,
816 if (!smooth) 828 if (!smooth)
817 { 829 {
818 lo.scale_load.smooth = 1; 830 lo.scale_load.smooth = 1;
819 _create_hash_key(hkey, im->file, pathlen, im->key, keylen, &lo); 831 evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
832 im->key, keylen, &lo);
820 833
821 ret = eina_hash_find(im->cache2->activ, hkey); 834 ret = eina_hash_find(im->cache2->activ, hkey);
822 if (ret) goto found; 835 if (ret) goto found;
@@ -827,7 +840,8 @@ _scaled_image_find(Image_Entry *im, int src_x, int src_y, int src_w, int src_h,
827 lo.scale_load.smooth = smooth; 840 lo.scale_load.smooth = smooth;
828 } 841 }
829 842
830 _create_hash_key(hkey, im->file, pathlen, im->key, keylen, &lo); 843 evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
844 im->key, keylen, &lo);
831 845
832 ret = eina_hash_find(im->cache2->activ, hkey); 846 ret = eina_hash_find(im->cache2->activ, hkey);
833 if (ret) goto found; 847 if (ret) goto found;
@@ -838,8 +852,8 @@ _scaled_image_find(Image_Entry *im, int src_x, int src_y, int src_w, int src_h,
838 if (!ret) return NULL; 852 if (!ret) return NULL;
839 853
840 /* Remove from lru and make it active again */ 854 /* Remove from lru and make it active again */
841 _evas_cache_image_lru_del(ret); 855 _evas_cache2_image_lru_del(ret);
842 _evas_cache_image_activ_add(ret); 856 _evas_cache2_image_activ_add(ret);
843 857
844 found: 858 found:
845 ret->references++; 859 ret->references++;
@@ -860,6 +874,9 @@ evas_cache2_image_scale_load(Image_Entry *im,
860 int error = EVAS_LOAD_ERROR_NONE; 874 int error = EVAS_LOAD_ERROR_NONE;
861 Image_Entry *ret; 875 Image_Entry *ret;
862 876
877 if (!im->cache2)
878 return im;
879
863 if (!smooth && im->scale_hint != EVAS_IMAGE_SCALE_HINT_STATIC) 880 if (!smooth && im->scale_hint != EVAS_IMAGE_SCALE_HINT_STATIC)
864 goto parent_out; 881 goto parent_out;
865 882
@@ -896,15 +913,16 @@ evas_cache2_image_scale_load(Image_Entry *im,
896 lo.scale_load.smooth = smooth; 913 lo.scale_load.smooth = smooth;
897 lo.scale_load.scale_hint = im->scale_hint; 914 lo.scale_load.scale_hint = im->scale_hint;
898 915
899 _create_hash_key(hkey, im->file, pathlen, im->key, keylen, &lo); 916 evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
917 im->key, keylen, &lo);
900 918
901 ret = _evas_cache_image_entry_new(im->cache2, hkey, NULL, im->file, im->key, 919 ret = _evas_cache2_image_entry_new(im->cache2, hkey, NULL, im->file, im->key,
902 &lo, &error); 920 &lo, &error);
903 if (error != EVAS_LOAD_ERROR_NONE) 921 if (error != EVAS_LOAD_ERROR_NONE)
904 { 922 {
905 ERR("Failed to create scale image entry with error code %d.", error); 923 ERR("Failed to create scale image entry with error code %d.", error);
906 924
907 if (ret) _evas_cache_image_entry_delete(im->cache2, ret); 925 if (ret) _evas_cache2_image_entry_delete(im->cache2, ret);
908 goto parent_out; 926 goto parent_out;
909 } 927 }
910 928
@@ -948,13 +966,13 @@ evas_cache2_image_close(Image_Entry *im)
948 if (references > 0) 966 if (references > 0)
949 return; 967 return;
950 968
951 if (im->flags.dirty) 969 if (im->flags.dirty || im->animated.animated)
952 { 970 {
953 _evas_cache_image_entry_delete(cache, im); 971 _evas_cache2_image_entry_delete(cache, im);
954 return; 972 return;
955 } 973 }
956 974
957 _evas_cache_image_lru_add(im); 975 _evas_cache2_image_lru_add(im);
958 if (cache) 976 if (cache)
959 evas_cache2_flush(cache); 977 evas_cache2_flush(cache);
960} 978}
@@ -965,7 +983,10 @@ evas_cache2_image_load_data(Image_Entry *ie)
965 int error = EVAS_LOAD_ERROR_NONE; 983 int error = EVAS_LOAD_ERROR_NONE;
966 984
967 if ((ie->flags.loaded) && (!ie->animated.animated)) 985 if ((ie->flags.loaded) && (!ie->animated.animated))
968 return error; 986 {
987 evas_cserve2_image_hit(ie);
988 return EVAS_LOAD_ERROR_NONE;
989 }
969 990
970 ie->flags.in_progress = EINA_TRUE; 991 ie->flags.in_progress = EINA_TRUE;
971 992
@@ -976,10 +997,10 @@ evas_cache2_image_load_data(Image_Entry *ie)
976 error = evas_cserve2_image_load_data_wait(ie); 997 error = evas_cserve2_image_load_data_wait(ie);
977 998
978 RGBA_Image *im = (RGBA_Image *)ie; 999 RGBA_Image *im = (RGBA_Image *)ie;
979 DBG("try cserve2 image data '%s' '%s' loaded!",
980 ie->file, ie->key ? ie->key : "");
981 if ((error == CSERVE2_NONE) && im->image.data) 1000 if ((error == CSERVE2_NONE) && im->image.data)
982 { 1001 {
1002 DBG("try cserve2 image data '%s' '%s' loaded!",
1003 ie->file, ie->key ? ie->key : "");
983 error = EVAS_LOAD_ERROR_NONE; 1004 error = EVAS_LOAD_ERROR_NONE;
984 } 1005 }
985 else 1006 else
@@ -1060,7 +1081,7 @@ evas_cache2_image_writable(Image_Entry *im)
1060 if (!im->cache_key) 1081 if (!im->cache_key)
1061 { 1082 {
1062 if (!im->flags.dirty) 1083 if (!im->flags.dirty)
1063 _evas_cache_image_dirty_add(im); 1084 _evas_cache2_image_dirty_add(im);
1064 return im; 1085 return im;
1065 } 1086 }
1066 1087
@@ -1075,7 +1096,7 @@ evas_cache2_image_writable(Image_Entry *im)
1075 1096
1076on_error: 1097on_error:
1077 if (im2) 1098 if (im2)
1078 _evas_cache_image_entry_delete(cache, im2); 1099 _evas_cache2_image_entry_delete(cache, im2);
1079 return NULL; 1100 return NULL;
1080} 1101}
1081 1102
@@ -1088,7 +1109,7 @@ evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigne
1088 if (!im->cache_key) 1109 if (!im->cache_key)
1089 { 1110 {
1090 if (!im->flags.dirty) 1111 if (!im->flags.dirty)
1091 _evas_cache_image_dirty_add(im); 1112 _evas_cache2_image_dirty_add(im);
1092 im2 = im; 1113 im2 = im;
1093 } 1114 }
1094 else 1115 else
@@ -1123,7 +1144,7 @@ evas_cache2_flush(Evas_Cache2 *cache)
1123 1144
1124 im = (Image_Entry *)cache->lru->last; 1145 im = (Image_Entry *)cache->lru->last;
1125 DBG("Remove unused entry from cache."); 1146 DBG("Remove unused entry from cache.");
1126 _evas_cache_image_entry_delete(cache, im); 1147 _evas_cache2_image_entry_delete(cache, im);
1127 } 1148 }
1128 1149
1129 return cache->usage; 1150 return cache->usage;
diff --git a/src/lib/evas/cache2/evas_cache2.h b/src/lib/evas/cache2/evas_cache2.h
index f6ba8f881e..7cd9c79170 100644
--- a/src/lib/evas/cache2/evas_cache2.h
+++ b/src/lib/evas/cache2/evas_cache2.h
@@ -66,6 +66,7 @@ EAPI void evas_cache2_image_close(Image_Entry *im);
66EAPI int evas_cache2_image_load_data(Image_Entry *ie); 66EAPI int evas_cache2_image_load_data(Image_Entry *ie);
67EAPI void evas_cache2_image_unload_data(Image_Entry *im); 67EAPI void evas_cache2_image_unload_data(Image_Entry *im);
68EAPI void evas_cache2_image_preload_data(Image_Entry *im, const void *target); 68EAPI void evas_cache2_image_preload_data(Image_Entry *im, const void *target);
69EAPI void evas_cache2_image_cache_key_create(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, const Evas_Image_Load_Opts *lo);
69 70
70EAPI DATA32 * evas_cache2_image_pixels(Image_Entry *im); 71EAPI DATA32 * evas_cache2_image_pixels(Image_Entry *im);
71EAPI Image_Entry * evas_cache2_image_writable(Image_Entry *im); 72EAPI Image_Entry * evas_cache2_image_writable(Image_Entry *im);
@@ -75,6 +76,7 @@ EAPI Image_Entry * evas_cache2_image_size_set(Image_Entry *im, unsigned int w, u
75EAPI Image_Entry * evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h); 76EAPI Image_Entry * evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
76EAPI Image_Entry * evas_cache2_image_empty(Evas_Cache2 *cache); 77EAPI Image_Entry * evas_cache2_image_empty(Evas_Cache2 *cache);
77EAPI void evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h); 78EAPI void evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h);
79EAPI Eina_Bool evas_cache2_image_cached(Image_Entry *ie);
78 80
79EAPI int evas_cache2_flush(Evas_Cache2 *cache); 81EAPI int evas_cache2_flush(Evas_Cache2 *cache);
80EAPI void evas_cache2_limit_set(Evas_Cache2 *cache, int limit); 82EAPI void evas_cache2_limit_set(Evas_Cache2 *cache, int limit);
diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c
index f755fccb0e..101b82f601 100644
--- a/src/lib/evas/canvas/evas_main.c
+++ b/src/lib/evas/canvas/evas_main.c
@@ -55,7 +55,11 @@ evas_init(void)
55 if (!evas_async_events_init()) 55 if (!evas_async_events_init())
56 goto shutdown_module; 56 goto shutdown_module;
57#ifdef EVAS_CSERVE2 57#ifdef EVAS_CSERVE2
58 if (getenv("EVAS_CSERVE2")) evas_cserve2_init(); 58 {
59 const char *env;
60 env = getenv("EVAS_CSERVE2");
61 if (env && atoi(env)) evas_cserve2_init();
62 }
59#endif 63#endif
60 _evas_preload_thread_init(); 64 _evas_preload_thread_init();
61 65
@@ -95,6 +99,11 @@ evas_shutdown(void)
95 EINA_LOG_STATE_START, 99 EINA_LOG_STATE_START,
96 EINA_LOG_STATE_SHUTDOWN); 100 EINA_LOG_STATE_SHUTDOWN);
97 101
102#ifdef EVAS_CSERVE2
103 if (evas_cserve2_use_get())
104 evas_cserve2_shutdown();
105#endif
106
98 eina_cow_del(evas_object_proxy_cow); 107 eina_cow_del(evas_object_proxy_cow);
99 eina_cow_del(evas_object_map_cow); 108 eina_cow_del(evas_object_map_cow);
100 eina_cow_del(evas_object_state_cow); 109 eina_cow_del(evas_object_state_cow);
diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c
index 5178e1b1a7..4e5cd3d391 100644
--- a/src/lib/evas/canvas/evas_object_image.c
+++ b/src/lib/evas/canvas/evas_object_image.c
@@ -3998,53 +3998,15 @@ evas_object_image_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, v
3998 (o->cur->border.b == 0) && 3998 (o->cur->border.b == 0) &&
3999 (o->cur->border.fill != 0)) 3999 (o->cur->border.fill != 0))
4000 { 4000 {
4001#ifdef EVAS_CSERVE2 4001 _draw_image
4002 if (evas_cserve2_use_get()) 4002 (obj, output, context, surface, pixels,
4003 { 4003 0, 0,
4004 Image_Entry *ie; 4004 imagew, imageh,
4005 void *data = pixels; 4005 obj->cur->geometry.x + ix + x,
4006 int w = imagew, h = imageh; 4006 obj->cur->geometry.y + iy + y,
4007 Eina_Bool mustclose = EINA_FALSE; 4007 iw, ih,
4008 4008 o->cur->smooth_scale,
4009 ie = evas_cache2_image_scale_load 4009 do_async);
4010 ((Image_Entry *)pixels,
4011 0, 0,
4012 imagew, imageh,
4013 iw, ih, o->cur->smooth_scale);
4014 if (ie != &((RGBA_Image *)pixels)->cache_entry)
4015 {
4016 data = ie;
4017 w = iw;
4018 h = ih;
4019 mustclose = EINA_TRUE;
4020 }
4021
4022 _draw_image
4023 (obj, output, context, surface, data,
4024 0, 0,
4025 w, h,
4026 obj->cur->geometry.x + ix + x,
4027 obj->cur->geometry.y + iy + y,
4028 iw, ih,
4029 o->cur->smooth_scale,
4030 do_async);
4031
4032 if (mustclose)
4033 evas_cache2_image_close(ie);
4034 }
4035 else
4036#endif
4037 {
4038 _draw_image
4039 (obj, output, context, surface, pixels,
4040 0, 0,
4041 imagew, imageh,
4042 obj->cur->geometry.x + ix + x,
4043 obj->cur->geometry.y + iy + y,
4044 iw, ih,
4045 o->cur->smooth_scale,
4046 do_async);
4047 }
4048 } 4010 }
4049 else 4011 else
4050 { 4012 {
diff --git a/src/lib/evas/canvas/evas_object_inform.c b/src/lib/evas/canvas/evas_object_inform.c
index c4aa8e199c..28ff355598 100644
--- a/src/lib/evas/canvas/evas_object_inform.c
+++ b/src/lib/evas/canvas/evas_object_inform.c
@@ -66,6 +66,8 @@ void
66evas_object_inform_call_image_preloaded(Evas_Object *eo_obj) 66evas_object_inform_call_image_preloaded(Evas_Object *eo_obj)
67{ 67{
68 Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJ_CLASS); 68 Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJ_CLASS);
69 EINA_SAFETY_ON_NULL_RETURN(obj);
70
69 if (!_evas_object_image_preloading_get(eo_obj)) return; 71 if (!_evas_object_image_preloading_get(eo_obj)) return;
70 _evas_object_image_preloading_check(eo_obj); 72 _evas_object_image_preloading_check(eo_obj);
71 _evas_object_image_preloading_set(eo_obj, 0); 73 _evas_object_image_preloading_set(eo_obj, 0);
diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c
index b08e0065f7..2ceca4da56 100644
--- a/src/lib/evas/canvas/evas_render.c
+++ b/src/lib/evas/canvas/evas_render.c
@@ -1571,7 +1571,7 @@ static Eina_Bool
1571_drop_image_cache_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED) 1571_drop_image_cache_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
1572{ 1572{
1573#ifdef EVAS_CSERVE2 1573#ifdef EVAS_CSERVE2
1574 if (evas_cserve2_use_get()) 1574 if (evas_cserve2_use_get() && evas_cache2_image_cached(data))
1575 evas_cache2_image_close((Image_Entry *)data); 1575 evas_cache2_image_close((Image_Entry *)data);
1576 else 1576 else
1577#endif 1577#endif
diff --git a/src/lib/evas/common/evas_font_draw.c b/src/lib/evas/common/evas_font_draw.c
index 5b8423db83..3a999ff23f 100644
--- a/src/lib/evas/common/evas_font_draw.c
+++ b/src/lib/evas/common/evas_font_draw.c
@@ -7,6 +7,10 @@
7 7
8#include "evas_font_ot.h" 8#include "evas_font_ot.h"
9 9
10#ifdef EVAS_CSERVE2
11#include "../cserve2/evas_cs2_private.h"
12#endif
13
10struct _Evas_Glyph 14struct _Evas_Glyph
11{ 15{
12 RGBA_Font_Glyph *fg; 16 RGBA_Font_Glyph *fg;
@@ -227,6 +231,19 @@ evas_common_font_rgba_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y,
227void 231void
228evas_common_font_glyphs_ref(Evas_Glyph_Array *array) 232evas_common_font_glyphs_ref(Evas_Glyph_Array *array)
229{ 233{
234#ifdef EVAS_CSERVE2
235 if (evas_cserve2_use_get() && !array->refcount)
236 {
237 Eina_Iterator *iter;
238 Evas_Glyph *glyph;
239
240 iter = eina_inarray_iterator_new(array->array);
241 EINA_ITERATOR_FOREACH(iter, glyph)
242 evas_cserve2_font_glyph_ref(glyph->fg->glyph_out, EINA_TRUE);
243 eina_iterator_free(iter);
244 }
245#endif
246
230 array->refcount++; 247 array->refcount++;
231} 248}
232 249
@@ -235,6 +252,19 @@ evas_common_font_glyphs_unref(Evas_Glyph_Array *array)
235{ 252{
236 if (--array->refcount) return; 253 if (--array->refcount) return;
237 254
255#ifdef EVAS_CSERVE2
256 if (evas_cserve2_use_get())
257 {
258 Eina_Iterator *iter;
259 Evas_Glyph *glyph;
260
261 iter = eina_inarray_iterator_new(array->array);
262 EINA_ITERATOR_FOREACH(iter, glyph)
263 evas_cserve2_font_glyph_ref(glyph->fg->glyph_out, EINA_FALSE);
264 eina_iterator_free(iter);
265 }
266#endif
267
238 eina_inarray_free(array->array); 268 eina_inarray_free(array->array);
239 evas_common_font_int_unref(array->fi); 269 evas_common_font_int_unref(array->fi);
240 free(array); 270 free(array);
@@ -274,6 +304,18 @@ evas_common_font_draw_prepare(Evas_Text_Props *text_props)
274 if (text_props->len < unit) unit = text_props->len; 304 if (text_props->len < unit) unit = text_props->len;
275 if (text_props->glyphs && text_props->glyphs->refcount == 1) 305 if (text_props->glyphs && text_props->glyphs->refcount == 1)
276 { 306 {
307#ifdef EVAS_CSERVE2
308 if (evas_cserve2_use_get())
309 {
310 Eina_Iterator *iter;
311 Evas_Glyph *glyph;
312
313 iter = eina_inarray_iterator_new(text_props->glyphs->array);
314 EINA_ITERATOR_FOREACH(iter, glyph)
315 evas_cserve2_font_glyph_ref(glyph->fg->glyph_out, EINA_FALSE);
316 eina_iterator_free(iter);
317 }
318#endif
277 glyphs = text_props->glyphs->array; 319 glyphs = text_props->glyphs->array;
278 glyphs->len = 0; 320 glyphs->len = 0;
279 reused_glyphs = EINA_TRUE; 321 reused_glyphs = EINA_TRUE;
@@ -304,7 +346,16 @@ evas_common_font_draw_prepare(Evas_Text_Props *text_props)
304 346
305 fg = evas_common_font_int_cache_glyph_get(fi, idx); 347 fg = evas_common_font_int_cache_glyph_get(fi, idx);
306 if (!fg) continue; 348 if (!fg) continue;
307 if (!fg->glyph_out) evas_common_font_int_cache_glyph_render(fg); 349 if (!evas_common_font_int_cache_glyph_render(fg))
350 {
351 fg = NULL;
352 goto error;
353 }
354
355#ifdef EVAS_CSERVE2
356 if (evas_cserve2_use_get())
357 evas_cserve2_font_glyph_ref(fg->glyph_out, EINA_TRUE);
358#endif
308 359
309 glyph = eina_inarray_grow(glyphs, 1); 360 glyph = eina_inarray_grow(glyphs, 1);
310 if (!glyph) goto error; 361 if (!glyph) goto error;
diff --git a/src/lib/evas/common/evas_font_main.c b/src/lib/evas/common/evas_font_main.c
index 32c7e379b1..8bc9e68243 100644
--- a/src/lib/evas/common/evas_font_main.c
+++ b/src/lib/evas/common/evas_font_main.c
@@ -548,12 +548,21 @@ evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg)
548 fg->glyph_out = evas_cserve2_font_glyph_bitmap_get(fi->cs2_handler, 548 fg->glyph_out = evas_cserve2_font_glyph_bitmap_get(fi->cs2_handler,
549 fg->index, 549 fg->index,
550 fg->fi->hinting); 550 fg->fi->hinting);
551 if (fg->glyph_out) 551 if (!fg->glyph_out)
552 return EINA_TRUE; 552 {
553 if (!fi->fash) fi->fash = _fash_gl_new();
554 if (fi->fash) _fash_gl_add(fi->fash, fg->index, (void *)(-1));
555 free(fg);
556 return EINA_FALSE;
557 }
558 return EINA_TRUE;
553 } 559 }
554#endif 560#endif
555 561
556 /* no cserve2 case */ 562 /* no cserve2 case */
563 if (fg->glyph_out)
564 return EINA_TRUE;
565
557 FTLOCK(); 566 FTLOCK();
558 error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1); 567 error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1);
559 if (error) 568 if (error)
diff --git a/src/lib/evas/common/evas_image_load.c b/src/lib/evas/common/evas_image_load.c
index c945442be5..174f1b0e48 100644
--- a/src/lib/evas/common/evas_image_load.c
+++ b/src/lib/evas/common/evas_image_load.c
@@ -243,18 +243,10 @@ evas_common_load_rgba_image_module_from_file(Image_Entry *ie)
243 struct evas_image_foreach_loader_data fdata; 243 struct evas_image_foreach_loader_data fdata;
244 244
245#ifdef EVAS_CSERVE2 245#ifdef EVAS_CSERVE2
246 if (evas_cserve2_use_get()) 246 if (evas_cserve2_use_get() && evas_cache2_image_cached(ie))
247 { 247 CRIT("This function shouldn't be called anymore!");
248 ERR("This function shouldn't be called anymore!");
249 // DBG("try cserve2 '%s' '%s'", ie->file, ie->key ? ie->key : "");
250 // if (evas_cserve2_image_load(ie, ie->file, ie->key, &(ie->load_opts)))
251 // {
252 // DBG("try cserve2 '%s' '%s' loaded!",
253 // ie->file, ie->key ? ie->key : "");
254 // return EVAS_LOAD_ERROR_NONE;
255 // }
256 }
257#endif 248#endif
249
258 if (ie->f) 250 if (ie->f)
259 { 251 {
260 len = strlen(eina_file_filename_get(ie->f)); 252 len = strlen(eina_file_filename_get(ie->f));
@@ -368,25 +360,8 @@ evas_common_load_rgba_image_data_from_file(Image_Entry *ie)
368 if ((ie->flags.loaded) && (!ie->animated.animated)) return EVAS_LOAD_ERROR_GENERIC; 360 if ((ie->flags.loaded) && (!ie->animated.animated)) return EVAS_LOAD_ERROR_GENERIC;
369 361
370#ifdef EVAS_CSERVE2 362#ifdef EVAS_CSERVE2
371 if (ie->data1) 363 if (evas_cserve2_use_get() && evas_cache2_image_cached(ie))
372 { 364 CRIT("This function shouldn't be called anymore!");
373 ERR("This function shouldn't be called anymore!");
374 // DBG("try cserve2 image data '%s' '%s'",
375 // ie->file, ie->key ? ie->key : "");
376 // if (evas_cserve2_image_data_load(ie))
377 // {
378 // RGBA_Image *im = (RGBA_Image *)ie;
379 // im->image.data = evas_cserve2_image_data_get(ie);
380 // DBG("try cserve2 image data '%s' '%s' loaded!",
381 // ie->file, ie->key ? ie->key : "");
382 // if (im->image.data)
383 // {
384 // im->image.no_free = 1;
385 // return EVAS_LOAD_ERROR_NONE;
386 // }
387 // }
388 // return EVAS_LOAD_ERROR_GENERIC;
389 }
390#endif 365#endif
391 366
392 if (!ie->info.module) return EVAS_LOAD_ERROR_GENERIC; 367 if (!ie->info.module) return EVAS_LOAD_ERROR_GENERIC;
diff --git a/src/lib/evas/common/evas_image_scalecache.c b/src/lib/evas/common/evas_image_scalecache.c
index fc907614c8..1a8229f604 100644
--- a/src/lib/evas/common/evas_image_scalecache.c
+++ b/src/lib/evas/common/evas_image_scalecache.c
@@ -663,7 +663,7 @@ evas_common_rgba_image_scalecache_do_cbs(Image_Entry *ie, RGBA_Image *dst,
663 if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888) 663 if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
664 { 664 {
665#ifdef EVAS_CSERVE2 665#ifdef EVAS_CSERVE2
666 if (evas_cserve2_use_get()) 666 if (evas_cserve2_use_get() && evas_cache2_image_cached(&im->cache_entry))
667 evas_cache2_image_load_data(&im->cache_entry); 667 evas_cache2_image_load_data(&im->cache_entry);
668 else 668 else
669#endif 669#endif
@@ -759,6 +759,26 @@ evas_common_rgba_image_scalecache_do_cbs(Image_Entry *ie, RGBA_Image *dst,
759 } 759 }
760 } 760 }
761 } 761 }
762
763#ifdef EVAS_CSERVE2
764 if (sci->populate_me && (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
765 && evas_cserve2_use_get() && evas_cache2_image_cached(&im->cache_entry))
766 {
767 RGBA_Image *im2 = (RGBA_Image *) evas_cache2_image_scale_load
768 (&im->cache_entry, src_region_x, src_region_y,
769 src_region_w, src_region_h, dst_region_w, dst_region_h, smooth);
770 SLKL(cache_lock);
771 if (im2 != im)
772 {
773 sci->im = im2;
774 sci->populate_me = 0;
775 cache_list = eina_inlist_append(cache_list, (Eina_Inlist *)sci);
776 didpop = 1;
777 }
778 SLKU(cache_lock);
779 }
780#endif
781
762 if (sci->populate_me) 782 if (sci->populate_me)
763 { 783 {
764// INF("##! populate!"); 784// INF("##! populate!");
diff --git a/src/lib/evas/cserve2/evas_cs2.h b/src/lib/evas/cserve2/evas_cs2.h
index ad36b4e7fe..a6e59945f2 100644
--- a/src/lib/evas/cserve2/evas_cs2.h
+++ b/src/lib/evas/cserve2/evas_cs2.h
@@ -23,6 +23,7 @@ typedef enum {
23 CSERVE2_FONT_GLYPHS_USED, 23 CSERVE2_FONT_GLYPHS_USED,
24 CSERVE2_STATS, 24 CSERVE2_STATS,
25 CSERVE2_FONT_DEBUG, 25 CSERVE2_FONT_DEBUG,
26 CSERVE2_INDEX_LIST,
26 CSERVE2_ERROR 27 CSERVE2_ERROR
27} Message_Type; 28} Message_Type;
28 29
@@ -38,6 +39,7 @@ typedef enum {
38 CSERVE2_LOADER_DIED, 39 CSERVE2_LOADER_DIED,
39 CSERVE2_LOADER_EXEC_ERR, 40 CSERVE2_LOADER_EXEC_ERR,
40 CSERVE2_INVALID_CACHE, // invalid cserve cache entry 41 CSERVE2_INVALID_CACHE, // invalid cserve cache entry
42 CSERVE2_NOT_LOADED,
41 CSERVE2_FILE_CHANGED, 43 CSERVE2_FILE_CHANGED,
42 CSERVE2_REQUEST_CANCEL 44 CSERVE2_REQUEST_CANCEL
43} Error_Type; 45} Error_Type;
@@ -72,6 +74,7 @@ struct _Msg_Opened {
72 int loop_count; 74 int loop_count;
73 int loop_hint; /* include Evas.h? Copy the enum around? */ 75 int loop_hint; /* include Evas.h? Copy the enum around? */
74 Eina_Bool alpha : 1; 76 Eina_Bool alpha : 1;
77 Eina_Bool animated : 1;
75 } image; 78 } image;
76}; 79};
77 80
@@ -88,6 +91,10 @@ struct _Msg_Loaded {
88 int mmap_size; 91 int mmap_size;
89 int image_size; 92 int image_size;
90 } shm; 93 } shm;
94 struct {
95 unsigned int w, h; // Real dimensions of this image. May differ from Msg_Opened::image::{w,h} after scaling.
96 } image;
97 Eina_Bool alpha : 1;
91 Eina_Bool alpha_sparse : 1; 98 Eina_Bool alpha_sparse : 1;
92}; 99};
93 100
@@ -183,7 +190,6 @@ struct _Msg_Font_Glyphs_Request {
183 */ 190 */
184struct _Msg_Font_Glyphs_Loaded { 191struct _Msg_Font_Glyphs_Loaded {
185 Msg_Base base; 192 Msg_Base base;
186 unsigned int ncaches;
187}; 193};
188 194
189struct _Msg_Stats { 195struct _Msg_Stats {
@@ -224,13 +230,14 @@ struct _Msg_Stats {
224 } images; 230 } images;
225}; 231};
226 232
227/* 233/**
228 * @struct _Msg_Font_Debug 234 * @struct _Msg_Font_Debug
229 * 235 *
230 * Message from server containing all font cache info. 236 * Message from server containing all font cache info.
231 * 237 *
232 * Content of the message follows: 238 * Content of the message follows:
233 * 239 *
240 * * char fonts_index_path[64]
234 * * number of font entries; 241 * * number of font entries;
235 * * each font entry: 242 * * each font entry:
236 * - unsigned int filelen 243 * - unsigned int filelen
@@ -241,15 +248,15 @@ struct _Msg_Stats {
241 * - unsigned int size; 248 * - unsigned int size;
242 * - unsigned int dpi; 249 * - unsigned int dpi;
243 * - unsigned int unused; 250 * - unsigned int unused;
244 * - ncaches: 251 * - const char glyph_data_shm[64];
245 * - each cache: 252 * - const char glyph_mempool_shm[64];
246 * * usigned int shmnamelen; 253 * - unsigned int nglyphs;
247 * * const char shmname; 254 * - each glyph: Glyph_Data struct
248 * * unsigned int size; 255 * - unsigned int id;
249 * * unsigned int usage; 256 * - unsigned int refcount;
250 * * unsigned int nglyphs;
251 * * each glyph:
252 * - unsigned int index; 257 * - unsigned int index;
258 * - unsigned int shm_id; // shared string id
259 * - unsigned int buffer_id;
253 * - unsigned int offset; 260 * - unsigned int offset;
254 * - unsigned int size; 261 * - unsigned int size;
255 * - unsigned int rows; 262 * - unsigned int rows;
@@ -260,6 +267,136 @@ struct _Msg_Stats {
260 */ 267 */
261struct _Msg_Font_Debug { 268struct _Msg_Font_Debug {
262 Msg_Base base; 269 Msg_Base base;
270 char fonts_index_path[64];
271 int nfonts;
272};
273
274/**
275 * @brief The Msg_Index_List struct
276 *
277 * Message sent from the server, without request from the client,
278 * to inform all clients of the shared index files. Contains the paths
279 * to the latest File, Image and Font index shm.
280 *
281 * The paths contain only the filename used in the call to shm_open.
282 * All strings must be null-terminated.
283 */
284struct _Msg_Index_List {
285 Msg_Base base;
286 int generation_id;
287 char strings_index_path[64];
288 char strings_entries_path[64];
289 char files_index_path[64];
290 char images_index_path[64];
291 char fonts_index_path[64];
292};
293
294typedef struct _Shm_Object Shm_Object;
295typedef struct _Index_Entry Index_Entry;
296typedef struct _File_Data File_Data;
297typedef struct _Image_Data Image_Data;
298typedef struct _Font_Data Font_Data;
299typedef struct _Glyph_Data Glyph_Data;
300typedef struct _Shared_Array_Header Shared_Array_Header;
301typedef int string_t;
302#define SHMOBJECT unsigned int id; unsigned int refcount
303
304struct _Shared_Array_Header {
305 int32_t tag;
306 int32_t generation_id;
307 int32_t elemsize;
308 int32_t count;
309 int32_t emptyidx;
310 int32_t sortedidx;
311 int32_t _reserved1;
312 int32_t _reserved2;
313};
314
315struct _Shm_Object {
316 SHMOBJECT;
317};
318
319#define STRING_INDEX_ARRAY_TAG ('S' | 'T' << 8 | 'R' << 16 | 'N' << 24)
320#define STRING_MEMPOOL_FAKETAG ('S' | 'T' << 8 | 'R' << 16 | 'M' << 24)
321struct _Index_Entry {
322 SHMOBJECT;
323 // Block entry
324 int32_t length;
325 int32_t offset;
326 int32_t shmid;
327};
328
329#define FILE_DATA_ARRAY_TAG ('F' | 'I' << 8 | 'L' << 16 | 'E' << 24)
330struct _File_Data {
331 SHMOBJECT;
332 // Hash entry elements (see Evas_Image_Load_Opts)
333 string_t path;
334 string_t key;
335 struct {
336 struct {
337 unsigned int x, y, w, h;
338 } region;
339 double dpi;
340 unsigned int w, h;
341 int scale_down_by;
342 Eina_Bool orientation;
343 } lo;
344 // Properties set after opening the file
345 string_t loader_data; // Can also be set during open (force this loader)
346 int w, h;
347 int frame_count;
348 int loop_count;
349 int loop_hint;
350 Eina_Bool alpha : 1;
351 Eina_Bool invalid : 1;
352 Eina_Bool valid : 1;
353 Eina_Bool animated : 1;
354};
355
356#define IMAGE_DATA_ARRAY_TAG ('I' | 'M' << 8 | 'A' << 16 | 'G' << 24)
357struct _Image_Data {
358 SHMOBJECT;
359 uint32_t file_id;
360 string_t shm_id;
361 Evas_Image_Load_Opts opts;
362 uint32_t w, h;
363 Eina_Bool alpha : 1;
364 Eina_Bool alpha_sparse : 1;
365 Eina_Bool unused : 1;
366 Eina_Bool doload : 1;
367 Eina_Bool valid : 1;
368};
369
370#define FONT_DATA_ARRAY_TAG ('F' | 'O' << 8 | 'N' << 16 | 'T' << 24)
371struct _Font_Data {
372 SHMOBJECT;
373 string_t name;
374 string_t file;
375 string_t glyph_index_shm;
376 string_t mempool_shm;
377 uint32_t rend_flags;
378 uint32_t size;
379 uint32_t dpi;
380};
381
382#define GLYPH_DATA_ARRAY_TAG ('G' | 'L' << 8 | 'P' << 16 | 'H' << 24)
383struct _Glyph_Data {
384 // Index_Entry
385 SHMOBJECT;
386 int32_t length;
387 int32_t offset;
388 int32_t shmid;
389 // Glyph data stuff
390 uint32_t index;
391 string_t mempool_id; // TODO: Merge with shmid? (Internally impossible atm)
392 uint32_t buffer_id;
393 uint32_t size;
394 uint32_t rows;
395 uint32_t width;
396 uint32_t pitch;
397 uint32_t num_grays;
398 uint32_t pixel_mode;
399 uint32_t hint;
263}; 400};
264 401
265struct _Msg_Error { 402struct _Msg_Error {
@@ -282,6 +419,7 @@ typedef struct _Msg_Font_Glyphs_Loaded Msg_Font_Glyphs_Loaded;
282typedef struct _Msg_Stats Msg_Stats; 419typedef struct _Msg_Stats Msg_Stats;
283typedef struct _Msg_Font_Debug Msg_Font_Debug; 420typedef struct _Msg_Font_Debug Msg_Font_Debug;
284typedef struct _Msg_Error Msg_Error; 421typedef struct _Msg_Error Msg_Error;
422typedef struct _Msg_Index_List Msg_Index_List;
285 423
286#endif 424#endif
287#endif 425#endif
diff --git a/src/lib/evas/cserve2/evas_cs2_client.c b/src/lib/evas/cserve2/evas_cs2_client.c
index 9fde9412d8..67c597a0cf 100644
--- a/src/lib/evas/cserve2/evas_cs2_client.c
+++ b/src/lib/evas/cserve2/evas_cs2_client.c
@@ -17,15 +17,40 @@
17 17
18#ifdef EVAS_CSERVE2 18#ifdef EVAS_CSERVE2
19 19
20typedef void (*Op_Callback)(void *data, const void *msg, int size); 20#define TIMEOUT 1000
21#define USE_SHARED_INDEX 1
22#define SHARED_INDEX_ADD_TO_HASH 1
23#define HKEY_LOAD_OPTS_STR_LEN 215
24#define SPECIAL_RID_INDEX_LIST ((unsigned int) 0xFFFFFF42)
25
26typedef Eina_Bool (*Op_Callback)(void *data, const void *msg, int size);
27
28static const Evas_Image_Load_Opts empty_lo = {
29 { 0, 0, 0, 0 },
30 {
31 0, 0, 0, 0,
32 0, 0,
33 0,
34 0
35 },
36 0.0,
37 0, 0,
38 0,
39 0,
40
41 EINA_FALSE
42};
21 43
22struct _File_Entry { 44struct _File_Entry {
23 unsigned int file_id; 45 unsigned int file_id;
46 unsigned int server_file_id;
47 EINA_REFCOUNT;
48 Eina_Stringshare *hkey;
24}; 49};
25 50
26struct _Client_Request { 51struct _Client_Request {
27 Message_Type type; 52 Msg_Base *msg;
28 unsigned int rid; 53 int msg_size;
29 Op_Callback cb; 54 Op_Callback cb;
30 void *data; 55 void *data;
31}; 56};
@@ -35,12 +60,34 @@ typedef struct _Client_Request Client_Request;
35 60
36static int cserve2_init = 0; 61static int cserve2_init = 0;
37static int socketfd = -1; 62static int socketfd = -1;
63static int sr_size = 0;
64static int sr_got = 0;
65static char *sr_buf = NULL;
38 66
39static unsigned int _rid_count = 0; 67static unsigned int _rid_count = 0;
40static unsigned int _file_id = 0; 68static unsigned int _file_id = 0;
41static unsigned int _data_id = 0; 69static unsigned int _data_id = 0;
42 70
43static Eina_List *_requests = NULL; 71static Eina_List *_requests = NULL;
72static Eina_Hash *_file_entries = NULL;
73
74// Shared index table
75static Index_Table _index;
76static const char *_shared_string_get(int id);
77static const char *_shared_string_safe_get(int id); // Do not allow remap during search
78static Eina_Bool _string_index_refresh(void);
79static int _server_index_list_set(Msg_Base *data, int size);
80static const File_Data *_shared_file_data_get_by_id(unsigned int id);
81static const Shm_Object *_shared_index_item_get_by_id(Shared_Index *si, int elemsize, unsigned int id, Eina_Bool safe);
82static const File_Data *_shared_image_entry_file_data_find(Image_Entry *ie);
83static const Image_Data *_shared_image_entry_image_data_find(Image_Entry *ie);
84static const Font_Data *_shared_font_entry_data_find(Font_Entry *fe);
85static Eina_Bool _shared_index_remap_check(Shared_Index *si, int elemsize);
86
87static Eina_Bool _server_dispatch_until(unsigned int rid);
88unsigned int _image_load_server_send(Image_Entry *ie);
89static unsigned int _image_open_server_send(Image_Entry *ie);
90static unsigned int _glyph_request_server_send(Font_Entry *fe, Font_Hint_Flags hints, Eina_Bool used);
44 91
45#ifndef UNIX_PATH_MAX 92#ifndef UNIX_PATH_MAX
46#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)NULL)->sun_path) 93#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)NULL)->sun_path)
@@ -66,6 +113,15 @@ _memory_zero_cmp(void *data, size_t len)
66} 113}
67 114
68static void 115static void
116_file_entry_free(void *data)
117{
118 File_Entry *fentry = data;
119 if (!fentry) return;
120 eina_stringshare_del(fentry->hkey);
121 free(fentry);
122}
123
124static void
69_socket_path_set(char *path) 125_socket_path_set(char *path)
70{ 126{
71 char *env; 127 char *env;
@@ -155,6 +211,7 @@ _server_connect(void)
155#endif 211#endif
156 212
157 socketfd = s; 213 socketfd = s;
214 sr_size = 0;
158 215
159 DBG("connected to cserve2 server."); 216 DBG("connected to cserve2 server.");
160 return EINA_TRUE; 217 return EINA_TRUE;
@@ -166,15 +223,16 @@ _server_disconnect(void)
166 if (socketfd != -1) 223 if (socketfd != -1)
167 close(socketfd); 224 close(socketfd);
168 socketfd = -1; 225 socketfd = -1;
226 sr_size = 0;
169} 227}
170 228
171static void 229static void
172_request_answer_add(Message_Type type, unsigned int rid, Op_Callback cb, void *data) 230_request_answer_add(Msg_Base *msg, int size, Op_Callback cb, void *data)
173{ 231{
174 Client_Request *cr = calloc(1, sizeof(*cr)); 232 Client_Request *cr = calloc(1, sizeof(*cr));
175 233
176 cr->type = type; 234 cr->msg = msg;
177 cr->rid = rid; 235 cr->msg_size = size;
178 cr->cb = cb; 236 cr->cb = cb;
179 cr->data = data; 237 cr->data = data;
180 238
@@ -195,7 +253,7 @@ _server_safe_send(int fd, const void *data, int size)
195 { 253 {
196 if ((errno == EAGAIN) || (errno == EINTR)) 254 if ((errno == EAGAIN) || (errno == EINTR))
197 continue; 255 continue;
198 DBG("send() failed with error [%d] %s", errno, strerror(errno)); 256 ERR("send() failed with error %d %m", errno);
199 return EINA_FALSE; 257 return EINA_FALSE;
200 } 258 }
201 sent += ret; 259 sent += ret;
@@ -205,40 +263,177 @@ _server_safe_send(int fd, const void *data, int size)
205} 263}
206 264
207static Eina_Bool 265static Eina_Bool
208_server_send(const void *buf, int size, Op_Callback cb, void *data) 266_request_resend(unsigned int rid)
209{ 267{
210 const Msg_Base *msg; 268 Eina_List *l;
211 if (!_server_safe_send(socketfd, &size, sizeof(size))) 269 Client_Request *cr;
270 Eina_Bool found = EINA_FALSE;
271
272 DBG("Re-sending %d requests...", eina_list_count(_requests));
273 EINA_LIST_FOREACH(_requests, l, cr)
212 { 274 {
213 ERR("Couldn't send message size to server."); 275 if (rid)
214 return EINA_FALSE; 276 {
277 if (cr->msg->rid != rid)
278 continue;
279 found = EINA_TRUE;
280 }
281
282 DBG("Sending request %d again: type %d", cr->msg->rid, cr->msg->type);
283
284 if (!_server_safe_send(socketfd, &cr->msg_size, sizeof(cr->msg_size)))
285 return EINA_FALSE;
286 if (!_server_safe_send(socketfd, cr->msg, cr->msg_size))
287 return EINA_FALSE;
288
289 if (found) break;
215 } 290 }
216 if (!_server_safe_send(socketfd, buf, size)) 291
292 if (rid)
293 return found;
294
295 return EINA_TRUE;
296}
297
298static void
299_shared_index_close(Shared_Index *si)
300{
301 if (!si) return;
302
303 if (si->f)
217 { 304 {
218 ERR("Couldn't send message body to server."); 305 if (si->data)
219 return EINA_FALSE; 306 eina_file_map_free(si->f, si->data);
307 eina_file_close(si->f);
220 } 308 }
309 if (si->entries_by_hkey)
310 eina_hash_free(si->entries_by_hkey);
311 si->f = NULL;
312 si->data = NULL;
313 memset(si, 0, sizeof(Shared_Index));
314}
221 315
222 msg = buf; 316static void
223 switch (msg->type) 317_shared_index_close_all()
318{
319 DBG("Closing all index files");
320 if (_index.strings_entries.f)
321 {
322 if (_index.strings_entries.data)
323 eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data);
324 eina_file_close(_index.strings_entries.f);
325 _index.strings_entries.data = NULL;
326 _index.strings_entries.f = NULL;
327 }
328 _shared_index_close(&_index.strings_index);
329 _shared_index_close(&_index.files);
330 _shared_index_close(&_index.images);
331 _shared_index_close(&_index.fonts);
332 _index.generation_id = 0;
333}
334
335static Eina_Bool
336_server_reconnect()
337{
338 _shared_index_close_all();
339
340 errno = 0;
341 _server_disconnect();
342 if (!_server_connect())
343 goto on_error;
344
345 if (!_server_dispatch_until(SPECIAL_RID_INDEX_LIST))
346 goto on_error;
347
348 /* NOTE: (TODO?)
349 * Either we reopen all images & fonts now
350 * Or we wait until new data is required again to request cserve2 to load
351 * it for us. Not sure which approch is the best now.
352 * So, for the moment, we'll just wait until the client needs new data.
353 */
354
355 if (!_request_resend(0))
356 goto on_error;
357
358 INF("Successfully reconnected to cserve2");
359 return EINA_TRUE;
360
361on_error:
362 ERR("Unable to reconnect to server: %d %m", errno);
363 return EINA_FALSE;
364}
365
366static Eina_Bool
367_request_answer_required(int type, Eina_Bool *valid)
368{
369 switch (type)
224 { 370 {
225 case CSERVE2_OPEN: 371 case CSERVE2_OPEN:
226 case CSERVE2_LOAD: 372 case CSERVE2_LOAD:
227 case CSERVE2_PRELOAD: 373 case CSERVE2_PRELOAD:
228 case CSERVE2_FONT_LOAD: 374 case CSERVE2_FONT_LOAD:
229 case CSERVE2_FONT_GLYPHS_LOAD: 375 case CSERVE2_FONT_GLYPHS_LOAD:
230 _request_answer_add(msg->type, msg->rid, cb, data); 376 if (valid) *valid = EINA_TRUE;
231 break; 377 return EINA_TRUE;
378 case CSERVE2_CLOSE:
379 case CSERVE2_UNLOAD:
380 case CSERVE2_FONT_UNLOAD:
381 case CSERVE2_FONT_GLYPHS_USED:
382 if (valid) *valid = EINA_TRUE;
383 return EINA_FALSE;
232 default: 384 default:
233 break; 385 ERR("Invalid message type %d", type);
386 if (valid) *valid = EINA_FALSE;
387 return EINA_FALSE;
234 } 388 }
235
236 return EINA_TRUE;
237} 389}
238 390
239static int sr_size = 0; 391static Eina_Bool
240static int sr_got = 0; 392_server_send(void *buf, int size, Op_Callback cb, void *data)
241static char *sr_buf = NULL; 393{
394 Msg_Base *msg = buf;
395 int type = msg->type;
396 Eina_Bool valid = EINA_TRUE;
397
398 if (!_server_safe_send(socketfd, &size, sizeof(size)))
399 {
400 ERR("Couldn't send message size to server.");
401 goto on_error;
402 }
403 if (!_server_safe_send(socketfd, buf, size))
404 {
405 ERR("Couldn't send message body to server.");
406 goto on_error;
407 }
408
409 if (_request_answer_required(type, &valid))
410 _request_answer_add(msg, size, cb, data);
411 else
412 free(msg);
413
414 return valid;
415
416on_error:
417 if (!_request_answer_required(type, NULL))
418 return EINA_FALSE;
419 ERR("Socket error: %d %m", errno);
420 switch (errno)
421 {
422 case EPIPE:
423 case EBADF:
424 WRN("Trying to reconnect to server...");
425 if (!_server_reconnect())
426 {
427 free(buf);
428 return EINA_FALSE;
429 }
430 return _server_send(buf, size, cb, data);
431 default:
432 ERR("Can not recover from this error!");
433 free(buf);
434 return EINA_FALSE;
435 }
436}
242 437
243static void * 438static void *
244_server_read(int *size) 439_server_read(int *size)
@@ -246,12 +441,21 @@ _server_read(int *size)
246 int n; 441 int n;
247 void *ret; 442 void *ret;
248 443
444 if (socketfd < 0)
445 return NULL;
446
249 if (sr_size) 447 if (sr_size)
250 goto get_data; 448 goto get_data;
251 449
252 n = recv(socketfd, &sr_size, sizeof(sr_size), 0); 450 n = recv(socketfd, &sr_size, sizeof(sr_size), 0);
253 if (n < 0) 451 if (n < 0)
254 return NULL; 452 return NULL;
453 if (n == 0)
454 {
455 DBG("Socket connection closed by server.");
456 _server_disconnect();
457 return NULL;
458 }
255 459
256 sr_buf = malloc(sr_size); 460 sr_buf = malloc(sr_size);
257 461
@@ -279,6 +483,8 @@ evas_cserve2_init(void)
279 if (cserve2_init++) 483 if (cserve2_init++)
280 return cserve2_init; 484 return cserve2_init;
281 485
486 memset(&_index, 0, sizeof(_index));
487
282 DBG("Connecting to cserve2."); 488 DBG("Connecting to cserve2.");
283 if (!_server_connect()) 489 if (!_server_connect())
284 { 490 {
@@ -286,18 +492,33 @@ evas_cserve2_init(void)
286 return 0; 492 return 0;
287 } 493 }
288 494
495 _file_entries = eina_hash_string_superfast_new(EINA_FREE_CB(_file_entry_free));
289 return cserve2_init; 496 return cserve2_init;
290} 497}
291 498
292int 499int
293evas_cserve2_shutdown(void) 500evas_cserve2_shutdown(void)
294{ 501{
502 const char zeros[sizeof(Msg_Index_List)] = {0};
503 Msg_Index_List *empty = (Msg_Index_List *) zeros;
504
505 if (cserve2_init <= 0)
506 {
507 CRIT("cserve2 is already shutdown");
508 return -1;
509 }
510
295 if ((--cserve2_init) > 0) 511 if ((--cserve2_init) > 0)
296 return cserve2_init; 512 return cserve2_init;
297 513
298 DBG("Disconnecting from cserve2."); 514 DBG("Disconnecting from cserve2.");
515 empty->base.type = CSERVE2_INDEX_LIST;
516 _server_index_list_set((Msg_Base *) empty, sizeof(Msg_Index_List));
299 _server_disconnect(); 517 _server_disconnect();
300 518
519 eina_hash_free(_file_entries);
520 _file_entries = NULL;
521
301 return cserve2_init; 522 return cserve2_init;
302} 523}
303 524
@@ -324,6 +545,7 @@ _server_dispatch(Eina_Bool *failed)
324 Eina_List *l, *l_next; 545 Eina_List *l, *l_next;
325 Client_Request *cr; 546 Client_Request *cr;
326 Msg_Base *msg; 547 Msg_Base *msg;
548 Eina_Bool found;
327 549
328 msg = _server_read(&size); 550 msg = _server_read(&size);
329 if (!msg) 551 if (!msg)
@@ -333,20 +555,41 @@ _server_dispatch(Eina_Bool *failed)
333 } 555 }
334 *failed = EINA_FALSE; 556 *failed = EINA_FALSE;
335 557
558 // Special messages (no request)
559 switch (msg->type)
560 {
561 case CSERVE2_INDEX_LIST:
562 _server_index_list_set(msg, size);
563 free(msg);
564 return SPECIAL_RID_INDEX_LIST;
565 default:
566 break;
567 }
568
569 // Normal client to server requests
336 EINA_LIST_FOREACH_SAFE(_requests, l, l_next, cr) 570 EINA_LIST_FOREACH_SAFE(_requests, l, l_next, cr)
337 { 571 {
338 if (cr->rid != msg->rid) // dispatch this answer 572 Eina_Bool remove = EINA_TRUE;
573
574 if (cr->msg->rid != msg->rid) // dispatch this answer
339 continue; 575 continue;
340 576
341 _requests = eina_list_remove_list(_requests, l); 577 found = EINA_TRUE;
342 if (cr->cb) 578 if (cr->cb)
343 cr->cb(cr->data, msg, size); 579 remove = cr->cb(cr->data, msg, size);
344 free(cr); 580 if (remove)
581 {
582 _requests = eina_list_remove_list(_requests, l);
583 free(cr->msg);
584 free(cr);
585 }
345 } 586 }
346 587
347 rid = msg->rid; 588 rid = msg->rid;
348 free(msg); 589 if (!found)
590 WRN("Got unexpected response %d for request %d", msg->type, rid);
349 591
592 free(msg);
350 return rid; 593 return rid;
351} 594}
352 595
@@ -354,23 +597,34 @@ static Eina_Bool
354_server_dispatch_until(unsigned int rid) 597_server_dispatch_until(unsigned int rid)
355{ 598{
356 Eina_Bool failed; 599 Eina_Bool failed;
357 fd_set rfds;
358 unsigned int rrid; 600 unsigned int rrid;
359 struct timeval tv;
360 601
361 while (1) 602 while (1)
362 { 603 {
363 rrid = _server_dispatch(&failed); 604 rrid = _server_dispatch(&failed);
364 if (rrid == rid) break; 605 if (rrid == rid) break;
606#if TIMEOUT
365 else if (failed) 607 else if (failed)
366 { 608 {
609 fd_set rfds;
610 struct timeval tv;
367 int sel; 611 int sel;
368 612
613 if (socketfd == -1)
614 {
615 DBG("Reconnecting to server...");
616 if (!_server_connect())
617 {
618 ERR("Could not reconnect to cserve2!");
619 return EINA_FALSE;
620 }
621 }
622
369 //DBG("Waiting for request %d...", rid); 623 //DBG("Waiting for request %d...", rid);
370 FD_ZERO(&rfds); 624 FD_ZERO(&rfds);
371 FD_SET(socketfd, &rfds); 625 FD_SET(socketfd, &rfds);
372 tv.tv_sec = 1; 626 tv.tv_sec = TIMEOUT / 1000;
373 tv.tv_usec = 0; 627 tv.tv_usec = TIMEOUT * 1000;
374 sel = select(socketfd + 1, &rfds, NULL, NULL, &tv); 628 sel = select(socketfd + 1, &rfds, NULL, NULL, &tv);
375 if (sel == -1) 629 if (sel == -1)
376 { 630 {
@@ -392,11 +646,12 @@ _server_dispatch_until(unsigned int rid)
392 return EINA_FALSE; 646 return EINA_FALSE;
393 } 647 }
394 } 648 }
649#endif
395 } 650 }
396 return EINA_TRUE; 651 return EINA_TRUE;
397} 652}
398 653
399static void 654static Eina_Bool
400_image_opened_cb(void *data, const void *msg_received, int size) 655_image_opened_cb(void *data, const void *msg_received, int size)
401{ 656{
402 const Msg_Base *answer = msg_received; 657 const Msg_Base *answer = msg_received;
@@ -407,9 +662,16 @@ _image_opened_cb(void *data, const void *msg_received, int size)
407 * and so we would have to check that open_rid is equal to answer->rid. 662 * and so we would have to check that open_rid is equal to answer->rid.
408 * -- jpeg 663 * -- jpeg
409 */ 664 */
410 //DBG("Received OPENED for RID: %d [open_rid: %d]", answer->rid, ie->open_rid); 665 DBG("Received OPENED for RID: %d [open_rid: %d]", answer->rid, ie->open_rid);
666
667 if (ie->server_id && !ie->open_rid)
668 return EINA_TRUE;
669
411 if (answer->rid != ie->open_rid) 670 if (answer->rid != ie->open_rid)
412 WRN("Message rid (%d) differs from expected rid (open_rid: %d)", answer->rid, ie->open_rid); 671 {
672 WRN("Message rid (%d) differs from expected rid (open_rid: %d)", answer->rid, ie->open_rid);
673 return EINA_TRUE;
674 }
413 ie->open_rid = 0; 675 ie->open_rid = 0;
414 676
415 if (answer->type != CSERVE2_OPENED) 677 if (answer->type != CSERVE2_OPENED)
@@ -424,14 +686,14 @@ _image_opened_cb(void *data, const void *msg_received, int size)
424 ERR("Invalid message type received: %d (%s)", answer->type, __FUNCTION__); 686 ERR("Invalid message type received: %d (%s)", answer->type, __FUNCTION__);
425 free(ie->data1); 687 free(ie->data1);
426 ie->data1 = NULL; 688 ie->data1 = NULL;
427 return; 689 return EINA_TRUE;
428 } 690 }
429 else if (size < (int) sizeof(*msg)) 691 else if (size < (int) sizeof(*msg))
430 { 692 {
431 ERR("Received message is too small"); 693 ERR("Received message is too small");
432 free(ie->data1); 694 free(ie->data1);
433 ie->data1 = NULL; 695 ie->data1 = NULL;
434 return; 696 return EINA_TRUE;
435 } 697 }
436 698
437 ie->w = msg->image.w; 699 ie->w = msg->image.w;
@@ -440,6 +702,9 @@ _image_opened_cb(void *data, const void *msg_received, int size)
440 ie->animated.loop_hint = msg->image.loop_hint; 702 ie->animated.loop_hint = msg->image.loop_hint;
441 ie->animated.loop_count = msg->image.loop_count; 703 ie->animated.loop_count = msg->image.loop_count;
442 ie->animated.frame_count = msg->image.frame_count; 704 ie->animated.frame_count = msg->image.frame_count;
705 ie->animated.animated = msg->image.animated;
706
707 return EINA_TRUE;
443} 708}
444 709
445static void 710static void
@@ -493,22 +758,29 @@ fail:
493 ie->data2 = NULL; 758 ie->data2 = NULL;
494} 759}
495 760
496static void 761static Eina_Bool
497_image_loaded_cb(void *data, const void *msg_received, int size) 762_image_loaded_cb(void *data, const void *msg_received, int size)
498{ 763{
499 const Msg_Base *answer = msg_received; 764 const Msg_Base *answer = msg_received;
500 const Msg_Loaded *msg = msg_received; 765 const Msg_Loaded *msg = msg_received;
501 Image_Entry *ie = data; 766 Image_Entry *ie = data;
502 767
503 //DBG("Received LOADED for RID: %d [load_rid: %d]", answer->rid, ie->load_rid); 768 DBG("Received LOADED for RID: %d [load_rid: %d]", answer->rid, ie->load_rid);
769
770 if (!ie->load_rid)
771 return EINA_TRUE;
772
504 if (answer->rid != ie->load_rid) 773 if (answer->rid != ie->load_rid)
505 WRN("Message rid (%d) differs from expected rid (load_rid: %d)", answer->rid, ie->load_rid); 774 {
775 WRN("Message rid (%d) differs from expected rid (load_rid: %d)", answer->rid, ie->load_rid);
776 return EINA_TRUE;
777 }
506 ie->load_rid = 0; 778 ie->load_rid = 0;
507 779
508 if (!ie->data2) 780 if (!ie->data2)
509 { 781 {
510 ERR("No data2 for loaded file"); 782 ERR("No data2 for loaded file");
511 return; 783 return EINA_TRUE;
512 } 784 }
513 785
514 if (answer->type != CSERVE2_LOADED) 786 if (answer->type != CSERVE2_LOADED)
@@ -518,18 +790,28 @@ _image_loaded_cb(void *data, const void *msg_received, int size)
518 const Msg_Error *msg_error = msg_received; 790 const Msg_Error *msg_error = msg_received;
519 ERR("Couldn't load image: '%s':'%s'; error: %d", 791 ERR("Couldn't load image: '%s':'%s'; error: %d",
520 ie->file, ie->key, msg_error->error); 792 ie->file, ie->key, msg_error->error);
793
794 if (msg_error->error == CSERVE2_NOT_LOADED)
795 {
796 DBG("Trying to reopen the image");
797 ie->open_rid = _image_open_server_send(ie);
798 if (_server_dispatch_until(ie->open_rid))
799 if (_request_resend(answer->rid))
800 return EINA_TRUE;
801 }
521 } 802 }
522 else 803 else
523 ERR("Invalid message type received: %d (%s)", answer->type, __FUNCTION__); 804 ERR("Invalid message type received: %d (%s)", answer->type, __FUNCTION__);
524 free(ie->data2); 805 free(ie->data2);
525 ie->data2 = NULL; 806 ie->data2 = NULL;
526 return; 807 return EINA_TRUE;
527 } 808 }
528 809
529 _loaded_handle(ie, msg, size); 810 _loaded_handle(ie, msg, size);
811 return EINA_TRUE;
530} 812}
531 813
532static void 814static Eina_Bool
533_image_preloaded_cb(void *data, const void *msg_received, int size) 815_image_preloaded_cb(void *data, const void *msg_received, int size)
534{ 816{
535 const Msg_Base *answer = msg_received; 817 const Msg_Base *answer = msg_received;
@@ -544,7 +826,7 @@ _image_preloaded_cb(void *data, const void *msg_received, int size)
544 if (!ie->data2) 826 if (!ie->data2)
545 { 827 {
546 ERR("No data2 for preloaded file"); 828 ERR("No data2 for preloaded file");
547 return; 829 return EINA_TRUE;
548 } 830 }
549 831
550 if (answer->type != CSERVE2_PRELOAD && 832 if (answer->type != CSERVE2_PRELOAD &&
@@ -561,7 +843,7 @@ _image_preloaded_cb(void *data, const void *msg_received, int size)
561 if (dentry->preloaded_cb) 843 if (dentry->preloaded_cb)
562 dentry->preloaded_cb(data, EINA_FALSE); 844 dentry->preloaded_cb(data, EINA_FALSE);
563 dentry->preloaded_cb = NULL; 845 dentry->preloaded_cb = NULL;
564 return; 846 return EINA_TRUE;
565 } 847 }
566 848
567 _loaded_handle(ie, msg_received, size); 849 _loaded_handle(ie, msg_received, size);
@@ -572,6 +854,8 @@ _image_preloaded_cb(void *data, const void *msg_received, int size)
572 dentry->preloaded_cb(data, EINA_TRUE); 854 dentry->preloaded_cb(data, EINA_TRUE);
573 dentry->preloaded_cb = NULL; 855 dentry->preloaded_cb = NULL;
574 } 856 }
857
858 return EINA_TRUE;
575} 859}
576 860
577static int 861static int
@@ -616,17 +900,64 @@ _build_absolute_path(const char *path, char buf[], int size)
616 return len; 900 return len;
617} 901}
618 902
903// NOTE: Copy & paste from evas_cserve2_cache.c (TODO: Merge into common file)
904static Eina_Bool
905_evas_image_load_opts_empty(Evas_Image_Load_Opts *lo)
906{
907 if (!lo) return EINA_TRUE;
908
909 return ((lo->scale_down_by == 0)
910 && (lo->dpi == 0.0)
911 && (lo->w == 0) && (lo->h == 0)
912 && (lo->region.x == 0) && (lo->region.y == 0)
913 && (lo->region.w == 0) && (lo->region.h == 0)
914 && (lo->orientation == 0)
915 && (lo->scale_load.src_x == 0) && (lo->scale_load.src_y == 0)
916 && (lo->scale_load.src_w == 0) && (lo->scale_load.src_h == 0)
917 && (lo->scale_load.dst_w == 0) && (lo->scale_load.dst_h == 0)
918 && (lo->scale_load.scale_hint == 0)); // Skip smooth
919}
920
921static void
922_file_hkey_get(char *buf, size_t sz, const char *path, const char *key,
923 Evas_Image_Load_Opts *lo)
924{
925 // Same as _evas_cache_image_loadopts_append() but not optimized :)
926 if (lo && _evas_image_load_opts_empty(lo))
927 lo = NULL;
928
929 if (!lo)
930 snprintf(buf, sz, "%s:%s", path, key);
931 else
932 {
933 if (lo->orientation)
934 {
935 snprintf(buf, sz, "%s:%s//@/%d/%f/%dx%d/%d+%d.%dx%d",
936 path, key, lo->scale_down_by, lo->dpi, lo->w, lo->h,
937 lo->region.x, lo->region.y, lo->region.w, lo->region.h);
938 }
939 else
940 {
941 snprintf(buf, sz, "%s:%s//@/%d/%f/%dx%d/%d+%d.%dx%d/o",
942 path, key, lo->scale_down_by, lo->dpi, lo->w, lo->h,
943 lo->region.x, lo->region.y, lo->region.w, lo->region.h);
944 }
945 }
946}
947
619static unsigned int 948static unsigned int
620_image_open_server_send(Image_Entry *ie, const char *file, const char *key, 949_image_open_server_send(Image_Entry *ie)
621 Evas_Image_Load_Opts *opts)
622{ 950{
623 int flen, klen; 951 int flen, klen;
624 int size; 952 int size, hkey_len;
625 char *buf; 953 char *buf;
626 char filebuf[PATH_MAX]; 954 char filebuf[PATH_MAX];
955 char *hkey;
627 Msg_Open msg_open; 956 Msg_Open msg_open;
628 File_Entry *fentry; 957 File_Entry *fentry;
629 Data_Entry *dentry; 958 Data_Entry *dentry;
959 const char *file, *key;
960 Evas_Image_Load_Opts *opts = NULL;
630 961
631 if (cserve2_init == 0) 962 if (cserve2_init == 0)
632 { 963 {
@@ -634,9 +965,15 @@ _image_open_server_send(Image_Entry *ie, const char *file, const char *key,
634 return 0; 965 return 0;
635 } 966 }
636 967
968 if (!_evas_image_load_opts_empty(&ie->load_opts))
969 opts = &ie->load_opts;
970
637 ie->data1 = NULL; 971 ie->data1 = NULL;
638 ie->data2 = NULL; 972 ie->data2 = NULL;
639 973
974 file = ie->file;
975 key = ie->key;
976
640 flen = _build_absolute_path(file, filebuf, sizeof(filebuf)); 977 flen = _build_absolute_path(file, filebuf, sizeof(filebuf));
641 if (!flen) 978 if (!flen)
642 { 979 {
@@ -646,23 +983,36 @@ _image_open_server_send(Image_Entry *ie, const char *file, const char *key,
646 flen++; 983 flen++;
647 984
648 if (!key) key = ""; 985 if (!key) key = "";
986 klen = strlen(key) + 1;
649 987
650 fentry = calloc(1, sizeof(*fentry)); 988 hkey_len = flen + klen + 1024;
989 hkey = alloca(hkey_len);
990 _file_hkey_get(hkey, hkey_len, filebuf, key, opts);
991 fentry = eina_hash_find(_file_entries, hkey);
651 if (!fentry) 992 if (!fentry)
652 return 0; 993 {
994 fentry = calloc(1, sizeof(*fentry));
995 if (!fentry)
996 return 0;
997
998 fentry->file_id = ++_file_id;
999 fentry->hkey = eina_stringshare_add(hkey);
1000 EINA_REFCOUNT_INIT(fentry);
1001 eina_hash_direct_add(_file_entries, fentry->hkey, fentry);
1002 }
1003 else
1004 EINA_REFCOUNT_REF(fentry);
653 1005
654 dentry = calloc(1, sizeof(*dentry)); 1006 dentry = calloc(1, sizeof(*dentry));
655 if (!dentry) 1007 if (!dentry)
656 { 1008 {
657 free(fentry); 1009 EINA_REFCOUNT_UNREF(fentry)
1010 eina_hash_del(_file_entries, fentry->hkey, fentry);
658 return 0; 1011 return 0;
659 } 1012 }
660 1013
661 memset(&msg_open, 0, sizeof(msg_open)); 1014 memset(&msg_open, 0, sizeof(msg_open));
662 1015
663 fentry->file_id = ++_file_id;
664 klen = strlen(key) + 1;
665
666 msg_open.base.rid = _next_rid(); 1016 msg_open.base.rid = _next_rid();
667 msg_open.base.type = CSERVE2_OPEN; 1017 msg_open.base.type = CSERVE2_OPEN;
668 msg_open.file_id = fentry->file_id; 1018 msg_open.file_id = fentry->file_id;
@@ -677,7 +1027,8 @@ _image_open_server_send(Image_Entry *ie, const char *file, const char *key,
677 buf = malloc(size); 1027 buf = malloc(size);
678 if (!buf) 1028 if (!buf)
679 { 1029 {
680 free(fentry); 1030 EINA_REFCOUNT_UNREF(fentry)
1031 eina_hash_del(_file_entries, fentry->hkey, fentry);
681 free(dentry); 1032 free(dentry);
682 return 0; 1033 return 0;
683 } 1034 }
@@ -690,15 +1041,13 @@ _image_open_server_send(Image_Entry *ie, const char *file, const char *key,
690 if (!_server_send(buf, size, _image_opened_cb, ie)) 1041 if (!_server_send(buf, size, _image_opened_cb, ie))
691 { 1042 {
692 ERR("Couldn't send message to server."); 1043 ERR("Couldn't send message to server.");
693 free(buf);
694 free(fentry);
695 free(dentry); 1044 free(dentry);
1045 EINA_REFCOUNT_UNREF(fentry)
1046 eina_hash_del(_file_entries, fentry->hkey, fentry);
696 return 0; 1047 return 0;
697 } 1048 }
698 1049
699 free(buf);
700 ie->data1 = fentry; 1050 ie->data1 = fentry;
701
702 dentry->image_id = msg_open.image_id; 1051 dentry->image_id = msg_open.image_id;
703 ie->data2 = dentry; 1052 ie->data2 = dentry;
704 1053
@@ -709,7 +1058,8 @@ unsigned int
709_image_load_server_send(Image_Entry *ie) 1058_image_load_server_send(Image_Entry *ie)
710{ 1059{
711 Data_Entry *dentry; 1060 Data_Entry *dentry;
712 Msg_Load msg; 1061 Msg_Load *msg;
1062 unsigned int rid;
713 1063
714 if (cserve2_init == 0) 1064 if (cserve2_init == 0)
715 return 0; 1065 return 0;
@@ -727,23 +1077,24 @@ _image_load_server_send(Image_Entry *ie)
727 return 0; 1077 return 0;
728 } 1078 }
729 1079
730 memset(&msg, 0, sizeof(msg)); 1080 msg = calloc(1, sizeof(Msg_Load));
731 1081 msg->base.rid = _next_rid();
732 msg.base.rid = _next_rid(); 1082 msg->base.type = CSERVE2_LOAD;
733 msg.base.type = CSERVE2_LOAD; 1083 msg->image_id = dentry->image_id;
734 msg.image_id = dentry->image_id;
735 1084
736 if (!_server_send(&msg, sizeof(msg), _image_loaded_cb, ie)) 1085 rid = msg->base.rid;
1086 if (!_server_send(msg, sizeof(Msg_Load), _image_loaded_cb, ie))
737 return 0; 1087 return 0;
738 1088
739 return msg.base.rid; 1089 return rid;
740} 1090}
741 1091
742unsigned int 1092unsigned int
743_image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success)) 1093_image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
744{ 1094{
745 Data_Entry *dentry; 1095 Data_Entry *dentry;
746 Msg_Preload msg; 1096 Msg_Preload *msg;
1097 unsigned int rid;
747 1098
748 if (cserve2_init == 0) 1099 if (cserve2_init == 0)
749 return 0; 1100 return 0;
@@ -756,23 +1107,24 @@ _image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_
756 } 1107 }
757 dentry->preloaded_cb = preloaded_cb; 1108 dentry->preloaded_cb = preloaded_cb;
758 1109
759 memset(&msg, 0, sizeof(msg)); 1110 msg = calloc(1, sizeof(Msg_Preload));
760 1111 msg->base.rid = _next_rid();
761 msg.base.rid = _next_rid(); 1112 msg->base.type = CSERVE2_PRELOAD;
762 msg.base.type = CSERVE2_PRELOAD; 1113 msg->image_id = dentry->image_id;
763 msg.image_id = dentry->image_id;
764 1114
765 if (!_server_send(&msg, sizeof(msg), _image_preloaded_cb, ie)) 1115 rid = msg->base.rid;
1116 if (!_server_send(msg, sizeof(Msg_Preload), _image_preloaded_cb, ie))
766 return 0; 1117 return 0;
767 1118
768 return msg.base.rid; 1119 return rid;
769} 1120}
770 1121
771unsigned int 1122unsigned int
772_image_close_server_send(Image_Entry *ie) 1123_image_close_server_send(Image_Entry *ie)
773{ 1124{
774 Msg_Close msg; 1125 Msg_Close *msg;
775 File_Entry *fentry; 1126 File_Entry *fentry;
1127 unsigned int rid;
776 1128
777 if (cserve2_init == 0) 1129 if (cserve2_init == 0)
778 return 0; 1130 return 0;
@@ -793,25 +1145,28 @@ _image_close_server_send(Image_Entry *ie)
793 ie->data2 = NULL; 1145 ie->data2 = NULL;
794 } 1146 }
795 1147
796 memset(&msg, 0, sizeof(msg)); 1148 msg = calloc(1, sizeof(Msg_Close));
797 msg.base.rid = _next_rid(); 1149 msg->base.rid = _next_rid();
798 msg.base.type = CSERVE2_CLOSE; 1150 msg->base.type = CSERVE2_CLOSE;
799 msg.file_id = fentry->file_id; 1151 msg->file_id = fentry->file_id;
800 1152
801 free(fentry); 1153 EINA_REFCOUNT_UNREF(fentry)
1154 eina_hash_del(_file_entries, fentry->hkey, fentry);
802 ie->data1 = NULL; 1155 ie->data1 = NULL;
803 1156
804 if (!_server_send(&msg, sizeof(msg), NULL, NULL)) 1157 rid = msg->base.rid;
1158 if (!_server_send(msg, sizeof(Msg_Close), NULL, NULL))
805 return 0; 1159 return 0;
806 1160
807 return msg.base.rid; 1161 return rid;
808} 1162}
809 1163
810unsigned int 1164unsigned int
811_image_unload_server_send(Image_Entry *ie) 1165_image_unload_server_send(Image_Entry *ie)
812{ 1166{
813 Msg_Unload msg; 1167 Msg_Unload *msg;
814 Data_Entry *dentry; 1168 Data_Entry *dentry;
1169 unsigned int rid;
815 1170
816 if (cserve2_init == 0) 1171 if (cserve2_init == 0)
817 return 0; 1172 return 0;
@@ -826,37 +1181,30 @@ _image_unload_server_send(Image_Entry *ie)
826 if (dentry->shm.f) 1181 if (dentry->shm.f)
827 eina_file_close(dentry->shm.f); 1182 eina_file_close(dentry->shm.f);
828 1183
829 // if (dentry->shm.path) 1184 msg = calloc(1, sizeof(Msg_Unload));
830 // free(dentry->shm.path); 1185 msg->base.rid = _next_rid();
831 memset(&msg, 0, sizeof(msg)); 1186 msg->base.type = CSERVE2_UNLOAD;
832 msg.base.rid = _next_rid(); 1187 msg->image_id = dentry->image_id;
833 msg.base.type = CSERVE2_UNLOAD;
834 msg.image_id = dentry->image_id;
835 1188
836 free(dentry); 1189 free(dentry);
837 ie->data2 = NULL; 1190 ie->data2 = NULL;
838 1191
839 if (!_server_send(&msg, sizeof(msg), NULL, NULL)) 1192 rid = msg->base.rid;
1193 if (!_server_send(msg, sizeof(Msg_Unload), NULL, NULL))
840 return 0; 1194 return 0;
841 1195
842 return msg.base.rid; 1196 return rid;
843} 1197}
844 1198
845Eina_Bool 1199Eina_Bool
846evas_cserve2_image_load(Image_Entry *ie) 1200evas_cserve2_image_load(Image_Entry *ie)
847{ 1201{
848 unsigned int rid; 1202 unsigned int rid;
849 const char *file, *key;
850 Evas_Image_Load_Opts *opts = NULL;
851 1203
852 if (!ie) 1204 if (!ie)
853 return EINA_FALSE; 1205 return EINA_FALSE;
854 1206
855 file = ie->file; 1207 rid = _image_open_server_send(ie);
856 key = ie->key;
857 if (!_memory_zero_cmp(&ie->load_opts, sizeof(ie->load_opts)))
858 opts = &ie->load_opts;
859 rid = _image_open_server_send(ie, file, key, opts);
860 if (!rid) 1208 if (!rid)
861 return EINA_FALSE; 1209 return EINA_FALSE;
862 1210
@@ -871,9 +1219,38 @@ evas_cserve2_image_load(Image_Entry *ie)
871int 1219int
872evas_cserve2_image_load_wait(Image_Entry *ie) 1220evas_cserve2_image_load_wait(Image_Entry *ie)
873{ 1221{
1222 const File_Data *fd;
1223 Eina_Bool failed;
1224 unsigned int rrid, rid;
1225
874 if (!ie) 1226 if (!ie)
875 return CSERVE2_GENERIC; 1227 return CSERVE2_GENERIC;
876 1228
1229 if (!ie->open_rid)
1230 return CSERVE2_NONE;
1231
1232 rid = ie->open_rid;
1233 rrid = _server_dispatch(&failed);
1234 if (rid == rrid)
1235 return CSERVE2_NONE;
1236
1237#if USE_SHARED_INDEX
1238 fd = _shared_image_entry_file_data_find(ie);
1239 if (fd && fd->valid)
1240 {
1241 DBG("Bypassing socket wait (open_rid %d)", ie->open_rid);
1242 ie->w = fd->w;
1243 ie->h = fd->h;
1244 ie->flags.alpha = fd->alpha;
1245 ie->animated.loop_hint = fd->loop_hint;
1246 ie->animated.loop_count = fd->loop_count;
1247 ie->animated.frame_count = fd->frame_count;
1248 ie->animated.animated = fd->animated;
1249 ie->server_id = fd->id;
1250 ie->open_rid = 0;
1251 }
1252#endif
1253
877 if (ie->open_rid) 1254 if (ie->open_rid)
878 { 1255 {
879 if (!_server_dispatch_until(ie->open_rid)) 1256 if (!_server_dispatch_until(ie->open_rid))
@@ -882,6 +1259,12 @@ evas_cserve2_image_load_wait(Image_Entry *ie)
882 return CSERVE2_GENERIC; 1259 return CSERVE2_GENERIC;
883 } 1260 }
884 1261
1262 if (ie->animated.animated)
1263 {
1264 WRN("This image is animated. cserve2 does not support animations");
1265 return CSERVE2_GENERIC;
1266 }
1267
885 return CSERVE2_NONE; 1268 return CSERVE2_NONE;
886} 1269}
887 1270
@@ -908,9 +1291,53 @@ evas_cserve2_image_data_load(Image_Entry *ie)
908int 1291int
909evas_cserve2_image_load_data_wait(Image_Entry *ie) 1292evas_cserve2_image_load_data_wait(Image_Entry *ie)
910{ 1293{
1294 const Image_Data *idata;
1295
911 if (!ie) 1296 if (!ie)
912 return CSERVE2_GENERIC; 1297 return CSERVE2_GENERIC;
913 1298
1299#if USE_SHARED_INDEX
1300 idata = _shared_image_entry_image_data_find(ie);
1301 if (idata && idata->valid)
1302 {
1303 // FIXME: Ugly copy & paste from _loaded_handle
1304 Data_Entry *dentry = ie->data2;
1305 RGBA_Image *im = (RGBA_Image *)ie;
1306 const char *shmpath;
1307
1308 shmpath = _shared_string_get(idata->shm_id);
1309 if (!shmpath) goto load_wait;
1310 DBG("Bypassing image load socket wait. Image found: %d in %s",
1311 idata->id, shmpath);
1312
1313 dentry->shm.mmap_offset = 0;
1314 dentry->shm.use_offset = 0;
1315 dentry->shm.f = eina_file_open(shmpath, EINA_TRUE);
1316 dentry->shm.mmap_size = eina_file_size_get(dentry->shm.f);
1317 dentry->shm.image_size = dentry->shm.mmap_size;
1318
1319 dentry->shm.data = eina_file_map_new(dentry->shm.f, EINA_FILE_WILLNEED,
1320 dentry->shm.mmap_offset,
1321 dentry->shm.mmap_size);
1322 if (!dentry->shm.data)
1323 {
1324 DBG("could not mmap the shm file: %d %m", errno);
1325 eina_file_close(dentry->shm.f);
1326 dentry->shm.f = NULL;
1327 goto load_wait;
1328 }
1329
1330 im->image.data = dentry->shm.data;
1331 ie->flags.alpha_sparse = idata->alpha_sparse;
1332 ie->flags.loaded = EINA_TRUE;
1333 im->image.no_free = 1;
1334
1335 ie->load_rid = 0;
1336 return CSERVE2_NONE;
1337 }
1338#endif
1339
1340load_wait:
914 if (ie->load_rid) 1341 if (ie->load_rid)
915 { 1342 {
916 if (!_server_dispatch_until(ie->load_rid)) 1343 if (!_server_dispatch_until(ie->load_rid))
@@ -976,9 +1403,12 @@ struct _Font_Entry
976 unsigned int dpi; 1403 unsigned int dpi;
977 Font_Rend_Flags wanted_rend; 1404 Font_Rend_Flags wanted_rend;
978 1405
1406 char *hkey;
1407 int font_data_id;
1408
979 unsigned int rid; // open 1409 unsigned int rid; // open
980 1410
981 Eina_Hash *glyphs_maps; 1411 Glyph_Map *map;
982 Fash_Glyph2 *fash[3]; // one per hinting value 1412 Fash_Glyph2 *fash[3]; // one per hinting value
983 1413
984 Eina_Clist glyphs_queue; 1414 Eina_Clist glyphs_queue;
@@ -992,11 +1422,10 @@ struct _Font_Entry
992struct _Glyph_Map 1422struct _Glyph_Map
993{ 1423{
994 Font_Entry *fe; 1424 Font_Entry *fe;
995 const char *name; 1425 Shared_Index index;
996 unsigned int size; 1426 Shared_Buffer mempool;
997 Eina_File *map;
998 unsigned char *data;
999 Eina_Clist glyphs; 1427 Eina_Clist glyphs;
1428 Eina_List *mempool_lru;
1000}; 1429};
1001 1430
1002struct _CS_Glyph_Out 1431struct _CS_Glyph_Out
@@ -1007,18 +1436,35 @@ struct _CS_Glyph_Out
1007 unsigned int idx; 1436 unsigned int idx;
1008 unsigned int rid; 1437 unsigned int rid;
1009 Glyph_Map *map; 1438 Glyph_Map *map;
1439 Shared_Buffer *sb;
1010 unsigned int offset; 1440 unsigned int offset;
1011 unsigned int size; 1441 unsigned int size;
1442 unsigned int hint;
1012 Eina_Bool used; 1443 Eina_Bool used;
1444 int pending_ref;
1445 EINA_REFCOUNT;
1013}; 1446};
1014 1447
1015static void 1448static void
1016_glyphs_map_free(Glyph_Map *m) 1449_glyphs_map_free(Glyph_Map *map)
1017{ 1450{
1018 eina_file_map_free(m->map, m->data); 1451 Shared_Buffer *mempool;
1019 eina_file_close(m->map); 1452
1020 eina_stringshare_del(m->name); 1453 if (!map) return;
1021 free(m); 1454
1455 EINA_LIST_FREE(map->mempool_lru, mempool)
1456 {
1457 eina_file_map_free(mempool->f, mempool->data);
1458 eina_file_close(mempool->f);
1459 free(mempool);
1460 }
1461 eina_file_map_free(map->mempool.f, map->mempool.data);
1462 eina_file_close(map->mempool.f);
1463 eina_file_map_free(map->index.f, map->index.data);
1464 eina_file_close(map->index.f);
1465 eina_hash_free(map->index.entries_by_hkey);
1466 map->fe->map = NULL;
1467 free(map);
1022} 1468}
1023 1469
1024static void 1470static void
@@ -1026,30 +1472,19 @@ _glyph_out_free(void *gl)
1026{ 1472{
1027 CS_Glyph_Out *glout = gl; 1473 CS_Glyph_Out *glout = gl;
1028 1474
1475 if (glout->used)
1476 eina_clist_remove(&glout->used_list);
1477
1029 if (glout->map) 1478 if (glout->map)
1030 { 1479 {
1031 // FIXME: Invalid write of size 8 here (64 bit machine)
1032 eina_clist_remove(&glout->map_entry); 1480 eina_clist_remove(&glout->map_entry);
1033 if (eina_clist_empty(&glout->map->glyphs)) 1481 if (eina_clist_empty(&glout->map->glyphs))
1034 { 1482 _glyphs_map_free(glout->map);
1035 eina_hash_del(glout->map->fe->glyphs_maps, &glout->map->name,
1036 NULL);
1037 _glyphs_map_free(glout->map);
1038 }
1039 } 1483 }
1040 1484
1041 free(glout); 1485 free(glout);
1042} 1486}
1043 1487
1044static Eina_Bool
1045_glyphs_maps_foreach_free(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
1046{
1047 Glyph_Map *m = data;
1048
1049 _glyphs_map_free(m);
1050 return EINA_TRUE;
1051}
1052
1053static void 1488static void
1054_font_entry_free(Font_Entry *fe) 1489_font_entry_free(Font_Entry *fe)
1055{ 1490{
@@ -1059,14 +1494,15 @@ _font_entry_free(Font_Entry *fe)
1059 if (fe->fash[i]) 1494 if (fe->fash[i])
1060 fash_gl_free(fe->fash[i]); 1495 fash_gl_free(fe->fash[i]);
1061 1496
1497 eina_hash_del_by_key(_index.fonts.entries_by_hkey, fe->hkey);
1498 free(fe->hkey);
1062 eina_stringshare_del(fe->source); 1499 eina_stringshare_del(fe->source);
1063 eina_stringshare_del(fe->name); 1500 eina_stringshare_del(fe->name);
1064 eina_hash_foreach(fe->glyphs_maps, _glyphs_maps_foreach_free, NULL); 1501 _glyphs_map_free(fe->map);
1065 eina_hash_free(fe->glyphs_maps);
1066 free(fe); 1502 free(fe);
1067} 1503}
1068 1504
1069static void 1505static Eina_Bool
1070_font_loaded_cb(void *data, const void *msg, int size) 1506_font_loaded_cb(void *data, const void *msg, int size)
1071{ 1507{
1072 const Msg_Base *m = msg; 1508 const Msg_Base *m = msg;
@@ -1077,6 +1513,8 @@ _font_loaded_cb(void *data, const void *msg, int size)
1077 if ((size < (int) sizeof(*m)) 1513 if ((size < (int) sizeof(*m))
1078 || (m->type == CSERVE2_ERROR)) 1514 || (m->type == CSERVE2_ERROR))
1079 fe->failed = EINA_TRUE; 1515 fe->failed = EINA_TRUE;
1516
1517 return EINA_TRUE;
1080} 1518}
1081 1519
1082static unsigned int 1520static unsigned int
@@ -1114,16 +1552,16 @@ _font_load_server_send(Font_Entry *fe, Message_Type type)
1114 if (type == CSERVE2_FONT_LOAD) 1552 if (type == CSERVE2_FONT_LOAD)
1115 cb = _font_loaded_cb; 1553 cb = _font_loaded_cb;
1116 1554
1117 if (_server_send(msg, size, cb, fe)) 1555 ret = msg->base.rid;
1118 ret = msg->base.rid; 1556 if (!_server_send(msg, size, cb, fe))
1119 1557 return 0;
1120 free(msg);
1121 1558
1122 return ret; 1559 return ret;
1123} 1560}
1124 1561
1125Font_Entry * 1562Font_Entry *
1126evas_cserve2_font_load(const char *source, const char *name, int size, int dpi, Font_Rend_Flags wanted_rend) 1563evas_cserve2_font_load(const char *source, const char *name, int size, int dpi,
1564 Font_Rend_Flags wanted_rend)
1127{ 1565{
1128 Font_Entry *fe; 1566 Font_Entry *fe;
1129 1567
@@ -1144,16 +1582,39 @@ evas_cserve2_font_load(const char *source, const char *name, int size, int dpi,
1144 return NULL; 1582 return NULL;
1145 } 1583 }
1146 1584
1147 fe->glyphs_maps = eina_hash_stringshared_new(NULL);
1148 eina_clist_init(&fe->glyphs_queue); 1585 eina_clist_init(&fe->glyphs_queue);
1149 eina_clist_init(&fe->glyphs_used); 1586 eina_clist_init(&fe->glyphs_used);
1150 1587
1588 if (asprintf(&fe->hkey, "%s:%s/%u:%u:%u", fe->name, fe->source,
1589 fe->size, fe->dpi, (unsigned int) fe->wanted_rend) == -1)
1590 fe->hkey = NULL;
1591
1151 return fe; 1592 return fe;
1152} 1593}
1153 1594
1154int 1595int
1155evas_cserve2_font_load_wait(Font_Entry *fe) 1596evas_cserve2_font_load_wait(Font_Entry *fe)
1156{ 1597{
1598#if USE_SHARED_INDEX
1599 const Font_Data *fd;
1600 Eina_Bool failed;
1601 unsigned int rid, rrid;
1602
1603 rid = fe->rid;
1604 rrid = _server_dispatch(&failed);
1605 if ((rid == rrid) && !fe->failed)
1606 return CSERVE2_NONE;
1607
1608 fd = _shared_font_entry_data_find(fe);
1609 if (fd)
1610 {
1611 DBG("Bypassing socket wait (rid %d)", fe->rid);
1612 fe->failed = EINA_FALSE;
1613 fe->rid = 0;
1614 return CSERVE2_NONE;
1615 }
1616#endif
1617
1157 if (!_server_dispatch_until(fe->rid)) 1618 if (!_server_dispatch_until(fe->rid))
1158 return CSERVE2_GENERIC; 1619 return CSERVE2_GENERIC;
1159 1620
@@ -1190,109 +1651,394 @@ typedef struct
1190 unsigned int rid; 1651 unsigned int rid;
1191} Glyph_Request_Data; 1652} Glyph_Request_Data;
1192 1653
1193static void 1654static Glyph_Map *
1655_glyph_map_open(Font_Entry *fe, const char *indexpath, const char *datapath)
1656{
1657 Glyph_Map *map;
1658
1659 if (!fe) return NULL;
1660 if (fe->map) return fe->map;
1661
1662 map = calloc(1, sizeof(*map));
1663 if (!map) return NULL;
1664
1665 map->fe = fe;
1666 eina_clist_init(&map->glyphs);
1667 eina_strlcpy(map->mempool.path, datapath, SHARED_BUFFER_PATH_MAX);
1668
1669 if (indexpath)
1670 {
1671 eina_strlcpy(map->index.path, indexpath, SHARED_BUFFER_PATH_MAX);
1672 map->index.generation_id = _index.generation_id;
1673 _shared_index_remap_check(&map->index, sizeof(Glyph_Data));
1674 }
1675
1676 map->mempool.f = eina_file_open(map->mempool.path, EINA_TRUE);
1677 map->mempool.size = eina_file_size_get(map->mempool.f);
1678 map->mempool.data = eina_file_map_all(map->mempool.f, EINA_FILE_RANDOM);
1679
1680 fe->map = map;
1681 return map;
1682}
1683
1684static Eina_Bool
1685_glyph_map_remap_check(Glyph_Map *map, const char *idxpath, const char *datapath)
1686{
1687 Eina_Bool changed = EINA_FALSE;
1688 Shared_Buffer *oldbuf = NULL;
1689 int oldcount;
1690
1691 // Note: Since the shm name contains cserve2's PID it should most likely
1692 // always change in case of crash/restart
1693
1694 if ((datapath && strcmp(datapath, map->mempool.path))
1695 || (idxpath && strcmp(idxpath, map->index.path)))
1696 {
1697 CS_Glyph_Out *gl, *cursor;
1698
1699 WRN("Glyph pool has changed location.");
1700
1701 // Force reopening index
1702 _shared_index_close(&map->index);
1703 eina_strlcpy(map->index.path, idxpath, SHARED_BUFFER_PATH_MAX);
1704
1705 // Reopen mempool
1706 if (EINA_REFCOUNT_GET(&map->mempool) > 0)
1707 {
1708 oldbuf = calloc(1, sizeof(Glyph_Map));
1709 oldbuf->f = map->mempool.f;
1710 oldbuf->data = map->mempool.data;
1711 oldbuf->size = map->mempool.size;
1712 eina_strlcpy(oldbuf->path, map->mempool.path, SHARED_BUFFER_PATH_MAX);
1713 map->mempool_lru = eina_list_append(map->mempool_lru, oldbuf);
1714 }
1715 else
1716 {
1717 eina_file_map_free(map->mempool.f, map->mempool.data);
1718 eina_file_close(map->mempool.f);
1719 }
1720
1721 eina_strlcpy(map->mempool.path, datapath, SHARED_BUFFER_PATH_MAX);
1722 map->mempool.f = eina_file_open(datapath, EINA_TRUE);
1723 map->mempool.data = eina_file_map_all(map->mempool.f, EINA_FILE_RANDOM);
1724 map->mempool.size = eina_file_size_get(map->mempool.f);
1725 EINA_REFCOUNT_GET(&map->mempool) = 0;
1726
1727 EINA_CLIST_FOR_EACH_ENTRY_SAFE(gl, cursor, &map->glyphs,
1728 CS_Glyph_Out, map_entry)
1729 {
1730 if (!EINA_REFCOUNT_GET(gl))
1731 {
1732 gl->sb = NULL;
1733 gl->base.bitmap.buffer = NULL;
1734 }
1735 else
1736 {
1737 gl->sb = oldbuf;
1738 EINA_REFCOUNT_REF(gl->sb);
1739 }
1740 }
1741
1742 if (!eina_clist_count(&map->glyphs))
1743 return EINA_TRUE;
1744
1745 map->index.generation_id = _index.generation_id;
1746 _shared_index_remap_check(&map->index, sizeof(Glyph_Data));
1747 return EINA_TRUE;
1748 }
1749 else if (eina_file_refresh(map->mempool.f) ||
1750 (eina_file_size_get(map->mempool.f) != (size_t) map->mempool.size))
1751 {
1752 CS_Glyph_Out *gl;
1753
1754 WRN("Glyph pool has been resized.");
1755
1756 // Queue old mempool into mempool_lru unless refcount == 0
1757 // We want to keep the old glyph bitmap data in memory because of
1758 // asynchronous rendering and also because remap could happen
1759 // after some glyphs have been requested but not all for the current
1760 // draw.
1761
1762 if (EINA_REFCOUNT_GET(&map->mempool) > 0)
1763 {
1764 oldbuf = calloc(1, sizeof(Glyph_Map));
1765 oldbuf->f = eina_file_dup(map->mempool.f);
1766 oldbuf->data = map->mempool.data;
1767 oldbuf->size = map->mempool.size;
1768 eina_strlcpy(oldbuf->path, map->mempool.path, SHARED_BUFFER_PATH_MAX);
1769 map->mempool_lru = eina_list_append(map->mempool_lru, oldbuf);
1770 }
1771 else
1772 eina_file_map_free(map->mempool.f, map->mempool.data);
1773 map->mempool.data = eina_file_map_all(map->mempool.f, EINA_FILE_RANDOM);
1774 map->mempool.size = eina_file_size_get(map->mempool.f);
1775 EINA_REFCOUNT_GET(&map->mempool) = 0;
1776
1777 // Remap unused but loaded glyphs
1778 EINA_CLIST_FOR_EACH_ENTRY(gl, &map->glyphs,
1779 CS_Glyph_Out, map_entry)
1780 {
1781 if (!EINA_REFCOUNT_GET(gl))
1782 {
1783 gl->sb = &map->mempool;
1784 gl->base.bitmap.buffer = (unsigned char *) gl->sb->data + gl->offset;
1785 }
1786 else if (oldbuf)
1787 {
1788 gl->sb = oldbuf;
1789 EINA_REFCOUNT_REF(gl->sb);
1790 }
1791 else
1792 ERR("Invalid refcounting here.");
1793 }
1794
1795 changed = EINA_TRUE;
1796 }
1797
1798 map->index.generation_id = _index.generation_id;
1799 oldcount = map->index.count;
1800 _shared_index_remap_check(&map->index, sizeof(Glyph_Data));
1801 changed |= (oldcount != map->index.count);
1802
1803 return changed;
1804}
1805
1806#if USE_SHARED_INDEX
1807static int
1808_font_entry_glyph_map_rebuild_check(Font_Entry *fe, Font_Hint_Flags hints)
1809{
1810 Eina_Bool changed = EINA_FALSE;
1811 int cnt = 0;
1812 const char *idxpath = NULL, *datapath = NULL;
1813
1814 _string_index_refresh();
1815 if (!fe->map)
1816 {
1817 const Font_Data *fd;
1818
1819 fd = _shared_font_entry_data_find(fe);
1820 if (!fd) return -1;
1821
1822 idxpath = _shared_string_safe_get(fd->glyph_index_shm);
1823 datapath = _shared_string_safe_get(fd->mempool_shm);
1824 if (!idxpath || !datapath) return -1;
1825
1826 fe->map =_glyph_map_open(fe, idxpath, datapath);
1827 changed = EINA_TRUE;
1828 }
1829
1830 changed |= _glyph_map_remap_check(fe->map, idxpath, datapath);
1831 if (changed && fe->map && fe->map->index.data && fe->map->mempool.data)
1832 {
1833 CS_Glyph_Out *gl;
1834 const Glyph_Data *gd;
1835 int k, tot = 0;
1836
1837 DBG("Rebuilding font hash based on shared index...");
1838 for (k = 0; k < fe->map->index.count; k++)
1839 {
1840 gd = &(fe->map->index.entries.gldata[k]);
1841 if (!gd->id) break;
1842 if (!gd->refcount) continue;
1843 if (gd->hint != hints) continue;
1844
1845 tot++;
1846 gl = fash_gl_find(fe->fash[hints], gd->index);
1847 if (gl && gl->base.bitmap.buffer) continue;
1848
1849 if (!gl)
1850 {
1851 gl = calloc(1, sizeof(*gl));
1852 gl->idx = gd->index;
1853 eina_clist_element_init(&gl->map_entry);
1854 eina_clist_element_init(&gl->used_list);
1855 fash_gl_add(fe->fash[hints], gl->idx, gl);
1856 }
1857 gl->map = fe->map;
1858 gl->sb = &fe->map->mempool;
1859 gl->offset = gd->offset;
1860 gl->size = gd->size;
1861 gl->hint = gd->hint;
1862 gl->base.bitmap.rows = gd->rows;
1863 gl->base.bitmap.width = gd->width;
1864 gl->base.bitmap.pitch = gd->pitch;
1865 gl->base.bitmap.buffer = (unsigned char *)
1866 fe->map->mempool.data + gl->offset;
1867 gl->base.bitmap.num_grays = gd->num_grays;
1868 gl->base.bitmap.pixel_mode = gd->pixel_mode;
1869 gl->idx = gd->index;
1870 gl->rid = 0;
1871
1872 if (!eina_clist_element_is_linked(&gl->map_entry))
1873 eina_clist_add_head(&fe->map->glyphs, &gl->map_entry);
1874 fash_gl_add(fe->fash[hints], gd->index, gl);
1875 cnt++;
1876 }
1877 if (cnt)
1878 DBG("Added %d glyphs to the font hash (out of %d scanned)", cnt, tot);
1879 }
1880
1881 return cnt;
1882}
1883#endif
1884
1885static Eina_Bool
1194_glyph_request_cb(void *data, const void *msg, int size) 1886_glyph_request_cb(void *data, const void *msg, int size)
1195{ 1887{
1196 const Msg_Font_Glyphs_Loaded *resp = msg; 1888 const Msg_Font_Glyphs_Loaded *resp = msg;
1197 Glyph_Request_Data *grd = data; 1889 Glyph_Request_Data *grd = data;
1198 Font_Entry *fe = grd->fe; 1890 Font_Entry *fe = grd->fe;
1199 unsigned int ncaches;
1200 const char *buf; 1891 const char *buf;
1892 int i, nglyphs;
1893 int shmname_len, idxname_len;
1894 const char *shmname, *idxname;
1895 int pos;
1201 1896
1202 if (resp->base.type == CSERVE2_ERROR) 1897 if (!fe || !fe->fash[grd->hints])
1203 goto end; 1898 goto end;
1204 1899
1205 if (!fe->fash[grd->hints]) 1900 if (resp->base.type == CSERVE2_ERROR)
1206 goto end; 1901 {
1902 const Msg_Error *err = msg;
1903 ERR("We got an error message when waiting for glyphs: %d", err->error);
1904
1905 if (err->error == CSERVE2_NOT_LOADED)
1906 {
1907 // This can happen in case cserve2 restarted.
1908 DBG("Reloading the font: %s from %s", fe->name, fe->source);
1909
1910 if (!(fe->rid = _font_load_server_send(fe, CSERVE2_FONT_LOAD)))
1911 {
1912 ERR("Failed to send font load message");
1913 free(data);
1914 return EINA_TRUE;
1915 }
1916
1917 if (fe->glyphs_queue_count)
1918 _glyph_request_server_send(fe, grd->hints, EINA_FALSE);
1919
1920 if (fe->glyphs_used_count)
1921 _glyph_request_server_send(fe, grd->hints, EINA_TRUE);
1922
1923 DBG("Resending glyph load message now...");
1924 if (!_request_resend(err->base.rid))
1925 {
1926 free(data);
1927 return EINA_TRUE;
1928 }
1929 // Keep this request in the list for now
1930 return EINA_FALSE;
1931 }
1932 free(data);
1933 return EINA_TRUE;
1934 }
1207 1935
1208 if (size <= (int) sizeof(*resp)) goto end; 1936 if (size <= (int) sizeof(*resp)) goto end;
1209 1937
1210 buf = (const char *)resp + sizeof(*resp); 1938 buf = (const char *)resp + sizeof(*resp);
1211 for (ncaches = 0; ncaches < resp->ncaches; ncaches++) 1939 pos = buf - (const char*) resp;
1212 {
1213 int i, nglyphs;
1214 int namelen;
1215 const char *name;
1216 Glyph_Map *map;
1217 int pos = buf - (const char*) resp;
1218 1940
1219 pos += sizeof(int); 1941 pos += sizeof(int);
1220 if (pos > size) goto end; 1942 if (pos > size) goto end;
1221 1943
1222 memcpy(&namelen, buf, sizeof(int)); 1944 memcpy(&shmname_len, buf, sizeof(int));
1223 buf += sizeof(int); 1945 buf += sizeof(int);
1224 1946
1225 pos += namelen + sizeof(int); 1947 pos += shmname_len + sizeof(int);
1226 if (pos > size) goto end; 1948 if (pos > size) goto end;
1227 1949
1228 name = eina_stringshare_add_length(buf, namelen); 1950 shmname = buf;
1229 buf += namelen; 1951 buf += shmname_len;
1230 1952
1231 memcpy(&nglyphs, buf, sizeof(int)); 1953 memcpy(&idxname_len, buf, sizeof(int));
1232 buf += sizeof(int); 1954 buf += sizeof(int);
1233 1955
1234 map = eina_hash_find(fe->glyphs_maps, name); 1956 pos += idxname_len + sizeof(int);
1235 if (!map) 1957 if (pos > size) goto end;
1958
1959 idxname = buf;
1960 buf += idxname_len;
1961
1962 memcpy(&nglyphs, buf, sizeof(int));
1963 buf += sizeof(int);
1964
1965 if (fe->map)
1966 _glyph_map_remap_check(fe->map, idxname, shmname);
1967
1968 if (!fe->map)
1969 fe->map = _glyph_map_open(fe, idxname, shmname);
1970
1971 for (i = 0; i < nglyphs; i++)
1972 {
1973 string_t shm_id;
1974 unsigned int idx, offset, glsize, hints;
1975 int rows, width, pitch, num_grays, pixel_mode;
1976 CS_Glyph_Out *gl;
1977
1978 pos = buf - (const char*) resp;
1979 pos += 8 * sizeof(int);
1980 if (pos > size) goto end;
1981
1982 memcpy(&idx, buf, sizeof(int));
1983 buf += sizeof(int);
1984 memcpy(&shm_id, buf, sizeof(string_t));
1985 buf += sizeof(string_t);
1986 memcpy(&offset, buf, sizeof(int));
1987 buf += sizeof(int);
1988 memcpy(&glsize, buf, sizeof(int));
1989 buf += sizeof(int);
1990 memcpy(&rows, buf, sizeof(int));
1991 buf += sizeof(int);
1992 memcpy(&width, buf, sizeof(int));
1993 buf += sizeof(int);
1994 memcpy(&pitch, buf, sizeof(int));
1995 buf += sizeof(int);
1996 memcpy(&num_grays, buf, sizeof(int));
1997 buf += sizeof(int);
1998 memcpy(&pixel_mode, buf, sizeof(int));
1999 buf += sizeof(int);
2000 memcpy(&hints, buf, sizeof(int));
2001 buf += sizeof(int);
2002 if (hints != grd->hints)
1236 { 2003 {
1237 map = calloc(1, sizeof(*map)); 2004 WRN("Invalid hints received: %d vs %d. Skip.", hints, grd->hints);
1238 map->fe = fe; 2005 continue;
1239 map->name = name;
1240 map->map = eina_file_open(name, EINA_TRUE);
1241 map->data = eina_file_map_all(map->map, EINA_FILE_WILLNEED);
1242 eina_clist_init(&map->glyphs);
1243 eina_hash_direct_add(fe->glyphs_maps, &map->name, map);
1244 } 2006 }
1245 else
1246 eina_stringshare_del(name);
1247 2007
1248 for (i = 0; i < nglyphs; i++) 2008 gl = fash_gl_find(fe->fash[hints], idx);
2009 if (!gl)
1249 { 2010 {
1250 unsigned int idx, offset, glsize; 2011 gl = calloc(1, sizeof(*gl));
1251 int rows, width, pitch, num_grays, pixel_mode; 2012 gl->idx = idx;
1252 CS_Glyph_Out *gl; 2013 eina_clist_element_init(&gl->map_entry);
1253 2014 eina_clist_element_init(&gl->used_list);
1254 pos = buf - (const char*) resp; 2015 fash_gl_add(fe->fash[hints], idx, gl);
1255 pos += 8 * sizeof(int);
1256 if (pos > size) goto end;
1257
1258 memcpy(&idx, buf, sizeof(int));
1259 buf += sizeof(int);
1260 memcpy(&offset, buf, sizeof(int));
1261 buf += sizeof(int);
1262 memcpy(&glsize, buf, sizeof(int));
1263 buf += sizeof(int);
1264 memcpy(&rows, buf, sizeof(int));
1265 buf += sizeof(int);
1266 memcpy(&width, buf, sizeof(int));
1267 buf += sizeof(int);
1268 memcpy(&pitch, buf, sizeof(int));
1269 buf += sizeof(int);
1270 memcpy(&num_grays, buf, sizeof(int));
1271 buf += sizeof(int);
1272 memcpy(&pixel_mode, buf, sizeof(int));
1273 buf += sizeof(int);
1274
1275 gl = fash_gl_find(fe->fash[grd->hints], idx);
1276 if (gl)
1277 {
1278 gl->map = map;
1279 gl->offset = offset;
1280 gl->size = glsize;
1281 gl->base.bitmap.rows = rows;
1282 gl->base.bitmap.width = width;
1283 gl->base.bitmap.pitch = pitch;
1284 gl->base.bitmap.buffer = map->data + gl->offset;
1285 gl->base.bitmap.num_grays = num_grays;
1286 gl->base.bitmap.pixel_mode = pixel_mode;
1287 gl->rid = 0;
1288
1289 eina_clist_add_head(&map->glyphs, &gl->map_entry);
1290 }
1291 } 2016 }
2017 gl->map = fe->map;
2018 gl->sb = &fe->map->mempool;
2019 gl->offset = offset;
2020 gl->size = glsize;
2021 gl->hint = hints;
2022 gl->base.bitmap.rows = rows;
2023 gl->base.bitmap.width = width;
2024 gl->base.bitmap.pitch = pitch;
2025 gl->base.bitmap.buffer =
2026 (unsigned char *) gl->map->mempool.data + gl->offset;
2027 gl->base.bitmap.num_grays = num_grays;
2028 gl->base.bitmap.pixel_mode = pixel_mode;
2029 gl->rid = 0;
2030
2031 if (!eina_clist_element_is_linked(&gl->map_entry))
2032 eina_clist_add_head(&fe->map->glyphs, &gl->map_entry);
1292 } 2033 }
1293 2034
2035 free(grd);
2036 return EINA_TRUE;
2037
1294end: 2038end:
2039 ERR("An unknown error occured when waiting for glyph data!");
1295 free(grd); 2040 free(grd);
2041 return EINA_TRUE;
1296} 2042}
1297 2043
1298static unsigned int 2044static unsigned int
@@ -1353,14 +2099,14 @@ _glyph_request_server_send(Font_Entry *fe, Font_Hint_Flags hints, Eina_Bool used
1353 if (!used) 2099 if (!used)
1354 { 2100 {
1355 gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, map_entry); 2101 gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, map_entry);
1356 gl->rid = msg->base.rid;
1357 eina_clist_remove(&gl->map_entry); 2102 eina_clist_remove(&gl->map_entry);
2103 gl->rid = msg->base.rid;
1358 } 2104 }
1359 else 2105 else
1360 { 2106 {
1361 gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, used_list); 2107 gl = EINA_CLIST_ENTRY(itr, CS_Glyph_Out, used_list);
1362 gl->used = EINA_FALSE;
1363 eina_clist_remove(&gl->used_list); 2108 eina_clist_remove(&gl->used_list);
2109 gl->used = EINA_FALSE;
1364 } 2110 }
1365 glyphs[nglyphs++] = gl->idx; 2111 glyphs[nglyphs++] = gl->idx;
1366 } 2112 }
@@ -1380,12 +2126,12 @@ _glyph_request_server_send(Font_Entry *fe, Font_Hint_Flags hints, Eina_Bool used
1380 else 2126 else
1381 cb = NULL; 2127 cb = NULL;
1382 2128
1383 if (_server_send(msg, size, cb, grd)) 2129 ret = msg->base.rid;
1384 ret = msg->base.rid; 2130 if (!_server_send(msg, size, cb, grd))
1385 else 2131 {
1386 free(grd); 2132 free(grd);
1387 2133 return 0;
1388 free(msg); 2134 }
1389 2135
1390 return ret; 2136 return ret;
1391} 2137}
@@ -1412,26 +2158,35 @@ evas_cserve2_font_glyph_request(Font_Entry *fe, unsigned int idx, Font_Hint_Flag
1412 } 2158 }
1413 2159
1414 glyph = fash_gl_find(fash, idx); 2160 glyph = fash_gl_find(fash, idx);
2161
2162 // Check map is still valid, otherwise we want to request the glyph again
2163 if (glyph && glyph->map && (&glyph->map->mempool != glyph->sb))
2164 {
2165 if (!EINA_REFCOUNT_GET(glyph))
2166 {
2167 fash_gl_del(fash, idx);
2168 glyph = NULL;
2169 }
2170 }
2171
1415 if (!glyph) 2172 if (!glyph)
1416 { 2173 {
1417 glyph = calloc(1, sizeof(*glyph)); 2174 glyph = calloc(1, sizeof(*glyph));
1418
1419 glyph->idx = idx; 2175 glyph->idx = idx;
1420
1421 fash_gl_add(fash, idx, glyph); 2176 fash_gl_add(fash, idx, glyph);
1422
1423 eina_clist_add_head(&fe->glyphs_queue, &glyph->map_entry); 2177 eina_clist_add_head(&fe->glyphs_queue, &glyph->map_entry);
1424 fe->glyphs_queue_count++; 2178 fe->glyphs_queue_count++;
1425 } 2179 }
1426 else if (!glyph->used) 2180 else if (!glyph->used)
1427 { 2181 {
2182 // This can happen in case of cserve2 restart. (corner case)
1428 eina_clist_add_head(&fe->glyphs_used, &glyph->used_list); 2183 eina_clist_add_head(&fe->glyphs_used, &glyph->used_list);
1429 fe->glyphs_used_count++; 2184 fe->glyphs_used_count++;
1430 glyph->used = EINA_TRUE; 2185 glyph->used = EINA_TRUE;
1431 } 2186 }
1432 2187
1433 /* FIXME crude way to manage a queue, but it will work for now */ 2188 /* FIXME crude way to manage a queue, but it will work for now */
1434 if (fe->glyphs_queue_count == 50) 2189 if (fe->glyphs_queue_count >= 50)
1435 _glyph_request_server_send(fe, hints, EINA_FALSE); 2190 _glyph_request_server_send(fe, hints, EINA_FALSE);
1436 2191
1437 return EINA_TRUE; 2192 return EINA_TRUE;
@@ -1462,9 +2217,25 @@ evas_cserve2_font_glyph_used(Font_Entry *fe, unsigned int idx, Font_Hint_Flags h
1462 if (!glyph) 2217 if (!glyph)
1463 return EINA_FALSE; 2218 return EINA_FALSE;
1464 2219
2220 // Glyph was requested but the bitmap data was not loaded yet.
1465 if (!glyph->map) 2221 if (!glyph->map)
1466 return EINA_TRUE; 2222 return EINA_TRUE;
1467 2223
2224 // Glyph was stored in a dead buffer. Need to reload it :)
2225 if (&glyph->map->mempool != glyph->sb)
2226 {
2227 if (!EINA_REFCOUNT_GET(glyph))
2228 {
2229 fash_gl_del(fash, idx);
2230 return EINA_FALSE;
2231 }
2232 else
2233 {
2234 // Keep old buffer, it is still valid.
2235 return EINA_TRUE;
2236 }
2237 }
2238
1468 if (glyph->used) 2239 if (glyph->used)
1469 return EINA_TRUE; 2240 return EINA_TRUE;
1470 2241
@@ -1476,7 +2247,8 @@ evas_cserve2_font_glyph_used(Font_Entry *fe, unsigned int idx, Font_Hint_Flags h
1476} 2247}
1477 2248
1478RGBA_Font_Glyph_Out * 2249RGBA_Font_Glyph_Out *
1479evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_Flags hints) 2250evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx,
2251 Font_Hint_Flags hints)
1480{ 2252{
1481 Fash_Glyph2 *fash; 2253 Fash_Glyph2 *fash;
1482 CS_Glyph_Out *out; 2254 CS_Glyph_Out *out;
@@ -1488,31 +2260,851 @@ evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_F
1488 if (fe->glyphs_queue_count) 2260 if (fe->glyphs_queue_count)
1489 _glyph_request_server_send(fe, hints, EINA_FALSE); 2261 _glyph_request_server_send(fe, hints, EINA_FALSE);
1490 2262
1491 if (fe->glyphs_used_count) 2263 if (fe->glyphs_used_count >= 50)
1492 _glyph_request_server_send(fe, hints, EINA_TRUE); 2264 _glyph_request_server_send(fe, hints, EINA_TRUE);
1493 2265
1494 fash = fe->fash[hints]; 2266 fash = fe->fash[hints];
1495 if (!fash) 2267 if (!fash)
1496 { 2268 {
1497 // this should not happen really, so let the user know he fucked up 2269 // this should not happen really, so let the user know he fucked up
1498 ERR("%s was called with a hinting value that was not requested!", __FUNCTION__); 2270 ERR("was called with a hinting value that was not requested!");
1499 return NULL; 2271 return NULL;
1500 } 2272 }
1501 2273
2274try_again:
1502 out = fash_gl_find(fash, idx); 2275 out = fash_gl_find(fash, idx);
1503 if (!out) 2276 if (!out)
1504 { 2277 {
1505 // again, if we are asking for a bitmap we were supposed to already 2278 // again, if we are asking for a bitmap we were supposed to already
1506 // have requested the glyph, it must be there 2279 // have requested the glyph, it must be there
1507 ERR("%s was called with a glyph index that was not requested!", __FUNCTION__); 2280 ERR("was called with a glyph index that was not requested!");
1508 return NULL; 2281 return NULL;
1509 } 2282 }
2283
2284 if (out->map && (&out->map->mempool != out->sb))
2285 {
2286 // If the map is not valid, this is a good time to reload the glyph.
2287 if (!EINA_REFCOUNT_GET(out))
2288 {
2289 fash_gl_del(fash, idx);
2290 if (!evas_cserve2_font_glyph_request(fe, idx, hints))
2291 return NULL;
2292
2293 DBG("Requesting again this glyph: %d", idx);
2294 goto try_again;
2295 }
2296 else // Can't reload now since the map is used.
2297 return &out->base;
2298 }
2299
2300
2301#if USE_SHARED_INDEX
2302 _font_entry_glyph_map_rebuild_check(fe, hints);
2303#endif
2304
1510 if (out->rid) 2305 if (out->rid)
1511 _server_dispatch_until(out->rid); 2306 if (!_server_dispatch_until(out->rid))
2307 {
2308 ERR("failed to load the requested glyphs, resending request");
2309 if (!_request_resend(out->rid))
2310 return NULL;
2311 }
1512 2312
1513 // promote shm and font entry in lru or something 2313 // promote shm and font entry in lru or something
1514
1515 return &(out->base); 2314 return &(out->base);
1516} 2315}
1517 2316
2317void
2318evas_cserve2_font_glyph_ref(RGBA_Font_Glyph_Out *glyph, Eina_Bool incref)
2319{
2320 CS_Glyph_Out *glout;
2321
2322 EINA_SAFETY_ON_FALSE_RETURN(evas_cserve2_use_get());
2323
2324 // glout = (CS_Glyph_Out *) glyph;
2325 glout = (CS_Glyph_Out *) (((char *) glyph) - offsetof(CS_Glyph_Out, base));
2326
2327 if (incref)
2328 {
2329 if (!glout->sb)
2330 {
2331 // This can happen when cserve2 restarted.
2332 glout->pending_ref++;
2333 return;
2334 }
2335 else if (!EINA_REFCOUNT_GET(glout))
2336 EINA_REFCOUNT_REF(glout->sb);
2337 if (glout->pending_ref)
2338 {
2339 EINA_REFCOUNT_GET(glout) += glout->pending_ref;
2340 glout->pending_ref = 0;
2341 }
2342 EINA_REFCOUNT_REF(glout);
2343 return;
2344 }
2345
2346 EINA_SAFETY_ON_FALSE_RETURN
2347 ((EINA_REFCOUNT_GET(glout) + glout->pending_ref) > 0);
2348
2349 if (!glout->sb)
2350 {
2351 glout->pending_ref--;
2352 return;
2353 }
2354
2355 if (glout->pending_ref)
2356 {
2357 if (!EINA_REFCOUNT_GET(glout) && (glout->pending_ref > 0))
2358 EINA_REFCOUNT_REF(glout->sb);
2359 EINA_REFCOUNT_GET(glout) += glout->pending_ref;
2360 glout->pending_ref = 0;
2361 }
2362
2363 EINA_REFCOUNT_UNREF(glout)
2364 {
2365 Eina_Bool noref = EINA_FALSE;
2366
2367 EINA_SAFETY_ON_FALSE_RETURN(EINA_REFCOUNT_GET(glout->sb) > 0);
2368 EINA_REFCOUNT_UNREF(glout->sb)
2369 noref = EINA_TRUE;
2370
2371 if (glout->sb != &glout->map->mempool)
2372 {
2373 if (noref)
2374 {
2375 DBG("Glyph shared buffer reached refcount 0. "
2376 "Unmapping %p from %s",
2377 glout->sb->data, glout->sb->path);
2378 glout->map->mempool_lru =
2379 eina_list_remove(glout->map->mempool_lru, glout->sb);
2380 eina_file_map_free(glout->sb->f, glout->sb->data);
2381 eina_file_close(glout->sb->f);
2382 free(glout->sb);
2383 }
2384 fash_gl_del(glout->map->fe->fash[glout->hint], glout->idx);
2385 }
2386 }
2387}
2388
2389
2390
2391// Fast access to shared index tables
2392
2393static Eina_Bool
2394_string_index_refresh(void)
2395{
2396 size_t sz;
2397 Eina_Bool ret = EINA_FALSE;
2398
2399 if (!_index.strings_entries.data
2400 && _index.strings_entries.path[0]
2401 && _index.strings_index.path[0])
2402 {
2403 _index.strings_entries.f = eina_file_open(_index.strings_entries.path, EINA_TRUE);
2404 if (_index.strings_entries.f)
2405 _index.strings_entries.size = eina_file_size_get(_index.strings_entries.f);
2406 else
2407 _index.strings_entries.size = 0;
2408 if (_index.strings_entries.size > 0)
2409 _index.strings_entries.data = eina_file_map_all(_index.strings_entries.f, EINA_FILE_RANDOM);
2410
2411 if (!_index.strings_entries.data)
2412 {
2413 ERR("Could not map strings entries from: '%s'", _index.strings_entries.path);
2414 if (_index.strings_entries.f) eina_file_close(_index.strings_entries.f);
2415 _index.strings_entries.f = NULL;
2416 _index.strings_entries.data = NULL;
2417 ret = EINA_FALSE;
2418 }
2419 else
2420 {
2421 DBG("Mapped string entries from %s", _index.strings_entries.path);
2422 ret = EINA_TRUE;
2423 }
2424 }
2425
2426 if (_index.strings_entries.data &&
2427 (!_index.strings_index.data && _index.strings_index.path[0]))
2428 {
2429 _index.strings_index.f = eina_file_open(_index.strings_index.path, EINA_TRUE);
2430 if (_index.strings_index.f)
2431 sz = eina_file_size_get(_index.strings_index.f);
2432 else
2433 {
2434 sz = 0;
2435 _index.strings_index.data = NULL;
2436 }
2437 if (sz >= sizeof(Shared_Array_Header))
2438 _index.strings_index.data = eina_file_map_all(_index.strings_index.f, EINA_FILE_RANDOM);
2439
2440 if (_index.strings_index.data)
2441 {
2442 DBG("Mapped string indexes from %s", _index.strings_index.path);
2443 sz = eina_file_size_get(_index.strings_index.f);
2444 _index.strings_index.count = (sz - sizeof(Shared_Array_Header)) / sizeof(Index_Entry);
2445 if (_index.strings_index.count > _index.strings_index.header->count)
2446 {
2447 WRN("Detected larger index than advertised: %d > %d",
2448 _index.strings_index.count, _index.strings_index.header->count);
2449 _index.strings_index.count = _index.strings_index.header->count;
2450 }
2451 ret = EINA_TRUE;
2452 }
2453 else
2454 {
2455 ERR("Could not map string indexes from %s", _index.strings_index.path);
2456 if (_index.strings_index.f) eina_file_close(_index.strings_index.f);
2457 if (_index.strings_entries.f)
2458 {
2459 if (_index.strings_entries.data)
2460 eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data);
2461 eina_file_close(_index.strings_entries.f);
2462 }
2463 _index.strings_index.f = NULL;
2464 _index.strings_entries.f = NULL;
2465 _index.strings_entries.data = NULL;
2466 ret = EINA_FALSE;
2467 }
2468 }
2469
2470 _shared_index_remap_check(&_index.strings_index, sizeof(Index_Entry));
2471 if (_index.strings_entries.data)
2472 {
2473 if (eina_file_refresh(_index.strings_entries.f)
2474 || (_index.strings_entries.size != (int) eina_file_size_get(_index.strings_entries.f)))
2475 {
2476 eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data);
2477 _index.strings_entries.data = eina_file_map_all(_index.strings_entries.f, EINA_FILE_RANDOM);
2478 _index.strings_entries.size = eina_file_size_get(_index.strings_entries.f);
2479 return EINA_TRUE;
2480 }
2481 }
2482
2483 return ret;
2484}
2485
2486// Returns the number of correctly opened index arrays
2487static int
2488_server_index_list_set(Msg_Base *data, int size)
2489{
2490 Msg_Index_List *msg = (Msg_Index_List *) data;
2491
2492 // TODO #1: Check populate rule.
2493 // TODO #2: Protect memory for read-only access.
2494 // TODO #3: Optimize file reopen/remap (esp. strings table)
2495
2496 if (size != sizeof(*msg) || msg->base.type != CSERVE2_INDEX_LIST)
2497 {
2498 CRIT("Invalid message! type: %d, size: %d (expected %d)",
2499 msg->base.type, size, (int) sizeof(*msg));
2500 return -1;
2501 }
2502
2503 if (_index.generation_id == msg->generation_id)
2504 {
2505 WRN("New index generation_id is the same as before: %d",
2506 _index.generation_id);
2507 }
2508
2509 _index.generation_id = msg->generation_id;
2510
2511 // 1. Strings (indexes and entries)
2512
2513 if (_index.strings_entries.data
2514 && strncmp(_index.strings_entries.path, msg->strings_entries_path,
2515 SHARED_BUFFER_PATH_MAX) != 0)
2516 {
2517 DBG("Updating string entries shm to: '%s'", msg->strings_entries_path);
2518 eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data);
2519 eina_file_close(_index.strings_entries.f);
2520 _index.strings_entries.f = NULL;
2521 _index.strings_entries.data = NULL;
2522 }
2523
2524 if (_index.strings_index.data
2525 && strncmp(_index.strings_index.path, msg->strings_index_path,
2526 SHARED_BUFFER_PATH_MAX) != 0)
2527 {
2528 DBG("Updating string indexes shm to: '%s'", msg->strings_index_path);
2529 _shared_index_close(&_index.strings_index);
2530 }
2531
2532 eina_strlcpy(_index.strings_entries.path, msg->strings_entries_path, SHARED_BUFFER_PATH_MAX);
2533 eina_strlcpy(_index.strings_index.path, msg->strings_index_path, SHARED_BUFFER_PATH_MAX);
2534 _string_index_refresh();
2535
2536
2537 // 2. File indexes
2538
2539 eina_strlcpy(_index.files.path, msg->files_index_path, SHARED_BUFFER_PATH_MAX);
2540 _shared_index_remap_check(&_index.files, sizeof(File_Data));
2541
2542
2543 // 3. Image indexes
2544
2545 eina_strlcpy(_index.images.path, msg->images_index_path, SHARED_BUFFER_PATH_MAX);
2546 _shared_index_remap_check(&_index.images, sizeof(Image_Data));
2547
2548
2549 // 4. Font indexes
2550
2551 eina_strlcpy(_index.fonts.path, msg->fonts_index_path, SHARED_BUFFER_PATH_MAX);
2552 _shared_index_remap_check(&_index.fonts, sizeof(Font_Data));
2553
2554 return 0;
2555}
2556
2557// FIXME: (almost) copy & paste from evas_cserve2_cache.c
2558static const char *
2559_shared_string_internal_get(int id, Eina_Bool safe)
2560{
2561 Index_Entry *ie;
2562
2563 if (!_index.strings_entries.data)
2564 {
2565 CRIT("Strings table is not valid: no data");
2566 return NULL;
2567 }
2568
2569 ie = (Index_Entry *)
2570 _shared_index_item_get_by_id(&_index.strings_index, sizeof(*ie), id, safe);
2571 if (!ie) return NULL;
2572 if (ie->offset < 0) return NULL;
2573 if (!ie->refcount) return NULL;
2574 if (ie->offset + ie->length > _index.strings_entries.size)
2575 {
2576 if (safe) return NULL;
2577 if (eina_file_refresh(_index.strings_entries.f)
2578 || (_index.strings_entries.size != (int) eina_file_size_get(_index.strings_entries.f)))
2579 {
2580 DBG("String entries size has changed from %d to %d",
2581 _index.strings_entries.size, (int) eina_file_size_get(_index.strings_entries.f));
2582 if (_string_index_refresh())
2583 return _shared_string_internal_get(id, EINA_FALSE);
2584 }
2585 return NULL;
2586 }
2587
2588 return _index.strings_entries.data + ie->offset;
2589}
2590
2591static const char *
2592_shared_string_safe_get(int id)
2593{
2594 return _shared_string_internal_get(id, EINA_TRUE);
2595}
2596
2597static const char *
2598_shared_string_get(int id)
2599{
2600 return _shared_string_internal_get(id, EINA_FALSE);
2601}
2602
2603#define SHARED_INDEX_CHECK(si, typ) \
2604 do { if (!_shared_index_remap_check(&(si), sizeof(typ))) { \
2605 CRIT("Failed to remap index"); return NULL; } } while (0)
2606
2607static const File_Data *
2608_shared_image_entry_file_data_find(Image_Entry *ie)
2609{
2610 const File_Data *fdata = NULL;
2611 File_Entry *fe;
2612 Eina_Bool add_to_hash = SHARED_INDEX_ADD_TO_HASH;
2613 char hkey[PATH_MAX];
2614 int k;
2615
2616 DBG("Trying to find if image '%s:%s' is already opened by cserve2",
2617 ie->file, ie->key);
2618
2619 SHARED_INDEX_CHECK(_index.files, File_Data);
2620
2621 if (!_index.strings_index.header || !_index.strings_entries.data)
2622 return NULL;
2623
2624 if (!_index.files.header || !_index.files.entries.filedata)
2625 return NULL;
2626
2627 // Direct access
2628 fe = ie->data1;
2629 if (fe->server_file_id)
2630 {
2631 if ((fdata = _shared_file_data_get_by_id(fe->server_file_id)) != NULL)
2632 return fdata;
2633 }
2634
2635 // Check hash
2636 _file_hkey_get(hkey, sizeof(hkey), ie->file, ie->key, &ie->load_opts);
2637 fdata = eina_hash_find(_index.files.entries_by_hkey, hkey);
2638 if (fdata)
2639 return fdata;
2640
2641 // Scan shared index
2642 _string_index_refresh();
2643 for (k = _index.files.last_entry_in_hash;
2644 k < _index.files.count && k < _index.files.header->emptyidx; k++)
2645 {
2646 const char *file, *key;
2647 const File_Data *fd;
2648 char fd_hkey[PATH_MAX];
2649 Evas_Image_Load_Opts lo = empty_lo;
2650
2651 fd = &(_index.files.entries.filedata[k]);
2652 if (!fd->id) break;
2653 if (!fd->refcount) continue;
2654
2655 key = _shared_string_safe_get(fd->key);
2656 file = _shared_string_safe_get(fd->path);
2657 if (!file)
2658 {
2659 ERR("Could not find filename for file %d: path id: %d",
2660 fd->id, fd->path);
2661 add_to_hash = EINA_FALSE;
2662 continue;
2663 }
2664
2665 lo.region.x = fd->lo.region.x;
2666 lo.region.y = fd->lo.region.y;
2667 lo.region.w = fd->lo.region.w;
2668 lo.region.h = fd->lo.region.h;
2669 lo.dpi = fd->lo.dpi;
2670 lo.w = fd->lo.w;
2671 lo.h = fd->lo.h;
2672 lo.scale_down_by = fd->lo.scale_down_by;
2673 lo.orientation = fd->lo.orientation;
2674
2675 _file_hkey_get(fd_hkey, sizeof(fd_hkey), file, key, &lo);
2676
2677 if (add_to_hash)
2678 {
2679 eina_hash_add(_index.files.entries_by_hkey, fd_hkey, fd);
2680 _index.files.last_entry_in_hash = k;
2681 }
2682
2683 if (!strcmp(hkey, fd_hkey))
2684 return fd;
2685 }
2686
2687 return NULL;
2688}
2689
2690static const Shm_Object *
2691_shared_index_item_get_by_id(Shared_Index *si, int elemsize, unsigned int id,
2692 Eina_Bool safe)
2693{
2694 const Shm_Object *obj;
2695 const char *base;
2696 int low = 0, high, start_high;
2697 int cur;
2698
2699 if (!si || elemsize <= 0 || !id)
2700 return NULL;
2701
2702 // FIXME: HACK (consider all arrays always sorted by id)
2703 high = si->header->emptyidx; // Should be si->header->sortedidx
2704
2705 if (high > si->count)
2706 {
2707 if ((!safe) && eina_file_refresh(si->f))
2708 {
2709 WRN("Refreshing indexes.");
2710 _string_index_refresh();
2711 _shared_index_remap_check(si, elemsize);
2712 high = MIN(si->header->emptyidx, si->count);
2713 }
2714 else
2715 high = si->count;
2716 }
2717
2718 base = si->data + sizeof(Shared_Array_Header);
2719
2720 // Direct access, works for non-repacked arrays
2721 if ((int) id < high)
2722 {
2723 obj = (Shm_Object *) (base + (elemsize * id));