summaryrefslogtreecommitdiff
path: root/src/lib/evas/cache2
diff options
context:
space:
mode:
authorVincent Torri <vincent.torri@gmail.com>2012-11-04 11:51:42 +0000
committerVincent Torri <vincent.torri@gmail.com>2012-11-04 11:51:42 +0000
commitc15e9c6575c3b5f39ded167dda5259de3de96151 (patch)
tree5115d7ae3620af24c2bc094cd062575af7adeda9 /src/lib/evas/cache2
parenta5ac6a987caec5a7f7596a25d0a065b9cc94c50c (diff)
merge: and now Evas
I've tested make -j 3 install and it works nicely I've tested expedite with software and opengl xlib, and it works. Not tested other engines, so please report any problems (engines or other) on the ML. TODO: examples and tests, I'll add them later ISSUE: Eina_Unicode size check. It indirectly depends on eina_config.h, which is created at the end of the configure script. So its size is always 0. I don't know how that size is used, so I can't do a lot, for now. SVN revision: 78895
Diffstat (limited to 'src/lib/evas/cache2')
-rw-r--r--src/lib/evas/cache2/evas_cache2.c958
-rw-r--r--src/lib/evas/cache2/evas_cache2.h87
2 files changed, 1045 insertions, 0 deletions
diff --git a/src/lib/evas/cache2/evas_cache2.c b/src/lib/evas/cache2/evas_cache2.c
new file mode 100644
index 0000000000..1b9d05cbd8
--- /dev/null
+++ b/src/lib/evas/cache2/evas_cache2.c
@@ -0,0 +1,958 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdlib.h>
6#include <assert.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <errno.h>
10
11#ifdef HAVE_EVIL
12# include <Evil.h>
13#endif
14
15#include "evas_common.h"
16#include "evas_private.h"
17#include "evas_cache2.h"
18#include "evas_cs2.h"
19#include "evas_cs2_private.h"
20
21#define FREESTRC(Var) \
22 if (Var) \
23{ \
24 eina_stringshare_del(Var); \
25 Var = NULL; \
26}
27
28static void _evas_cache_image_dirty_add(Image_Entry *im);
29static void _evas_cache_image_dirty_del(Image_Entry *im);
30static void _evas_cache_image_activ_add(Image_Entry *im);
31static void _evas_cache_image_activ_del(Image_Entry *im);
32static void _evas_cache_image_lru_add(Image_Entry *im);
33static void _evas_cache_image_lru_del(Image_Entry *im);
34static void _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target);
35// static void _evas_cache_image_lru_nodata_add(Image_Entry *im);
36// static void _evas_cache_image_lru_nodata_del(Image_Entry *im);
37
38static void
39_evas_cache_image_dirty_add(Image_Entry *im)
40{
41 if (im->flags.dirty) return;
42 _evas_cache_image_activ_del(im);
43 _evas_cache_image_lru_del(im);
44 // _evas_cache_image_lru_nodata_del(im);
45 im->flags.dirty = 1;
46 im->flags.cached = 1;
47 im->cache2->dirty = eina_inlist_prepend(im->cache2->dirty, EINA_INLIST_GET(im));
48 if (im->cache_key)
49 {
50 eina_stringshare_del(im->cache_key);
51 im->cache_key = NULL;
52 }
53}
54
55static void
56_evas_cache_image_dirty_del(Image_Entry *im)
57{
58 if (!im->flags.dirty) return;
59 if (!im->cache2) return;
60 im->flags.dirty = 0;
61 im->flags.cached = 0;
62 im->cache2->dirty = eina_inlist_remove(im->cache2->dirty, EINA_INLIST_GET(im));
63}
64
65static void
66_evas_cache_image_activ_add(Image_Entry *im)
67{
68 if (im->flags.activ) return;
69 _evas_cache_image_dirty_del(im);
70 _evas_cache_image_lru_del(im);
71 // _evas_cache_image_lru_nodata_del(im);
72 if (!im->cache_key) return;
73 im->flags.activ = 1;
74 im->flags.cached = 1;
75 eina_hash_direct_add(im->cache2->activ, im->cache_key, im);
76}
77
78static void
79_evas_cache_image_activ_del(Image_Entry *im)
80{
81 if (!im->flags.activ) return;
82 if (!im->cache_key) return;
83 im->flags.activ = 0;
84 im->flags.cached = 0;
85 eina_hash_del(im->cache2->activ, im->cache_key, im);
86}
87
88static void
89_evas_cache_image_lru_add(Image_Entry *im)
90{
91 if (im->flags.lru) return;
92 _evas_cache_image_dirty_del(im);
93 _evas_cache_image_activ_del(im);
94 // _evas_cache_image_lru_nodata_del(im);
95 if (!im->cache_key) return;
96 im->flags.lru = 1;
97 im->flags.cached = 1;
98 eina_hash_direct_add(im->cache2->inactiv, im->cache_key, im);
99 im->cache2->lru = eina_inlist_prepend(im->cache2->lru, EINA_INLIST_GET(im));
100 im->cache2->usage += im->cache2->func.mem_size_get(im);
101}
102
103static void
104_evas_cache_image_lru_del(Image_Entry *im)
105{
106 if (!im->flags.lru) return;
107 if (!im->cache_key) return;
108 im->flags.lru = 0;
109 im->flags.cached = 0;
110 eina_hash_del(im->cache2->inactiv, im->cache_key, im);
111 im->cache2->lru = eina_inlist_remove(im->cache2->lru, EINA_INLIST_GET(im));
112 im->cache2->usage -= im->cache2->func.mem_size_get(im);
113}
114
115/*
116static void
117_evas_cache_image_lru_nodata_add(Image_Entry *im)
118{
119 if (im->flags.lru_nodata) return;
120 _evas_cache_image_dirty_del(im);
121 _evas_cache_image_activ_del(im);
122 _evas_cache_image_lru_del(im);
123 im->flags.lru = 1;
124 im->flags.cached = 1;
125 im->cache2->lru_nodata = eina_inlist_prepend(im->cache2->lru_nodata, EINA_INLIST_GET(im));
126}
127
128static void
129_evas_cache_image_lru_nodata_del(Image_Entry *im)
130{
131 if (!im->flags.lru_nodata) return;
132 im->flags.lru = 0;
133 im->flags.cached = 0;
134 im->cache2->lru_nodata = eina_inlist_remove(im->cache2->lru_nodata, EINA_INLIST_GET(im));
135}
136*/
137
138static Eina_Bool
139_timestamp_compare(Image_Timestamp *tstamp, struct stat *st)
140{
141 if (tstamp->mtime != st->st_mtime) return EINA_FALSE;
142 if (tstamp->size != st->st_size) return EINA_FALSE;
143 if (tstamp->ino != st->st_ino) return EINA_FALSE;
144#ifdef _STAT_VER_LINUX
145#if (defined __USE_MISC && defined st_mtime)
146 if (tstamp->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec)
147 return EINA_FALSE;
148#else
149 if (tstamp->mtime_nsec != (unsigned long int)st->st_mtimensec)
150 return EINA_FALSE;
151#endif
152#endif
153 return EINA_TRUE;
154}
155
156static void
157_timestamp_build(Image_Timestamp *tstamp, struct stat *st)
158{
159 tstamp->mtime = st->st_mtime;
160 tstamp->size = st->st_size;
161 tstamp->ino = st->st_ino;
162#ifdef _STAT_VER_LINUX
163#if (defined __USE_MISC && defined st_mtime)
164 tstamp->mtime_nsec = (unsigned long int)st->st_mtim.tv_nsec;
165#else
166 tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec;
167#endif
168#endif
169}
170
171static void
172_evas_cache_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie)
173{
174 if (!ie) return;
175
176 if (ie->flags.delete_me == 1)
177 return;
178
179 if (ie->preload_rid)
180 {
181 ie->flags.delete_me = 1;
182 _evas_cache2_image_entry_preload_remove(ie, NULL);
183 return;
184 }
185
186 _evas_cache_image_dirty_del(ie);
187 _evas_cache_image_activ_del(ie);
188 _evas_cache_image_lru_del(ie);
189 // _evas_cache_image_lru_nodata_del(ie);
190
191
192 if (ie->data1)
193 {
194 evas_cserve2_image_unload(ie);
195 evas_cache2_image_unload_data(ie);
196 evas_cserve2_image_free(ie);
197 }
198 else
199 {
200 if (cache)
201 cache->func.surface_delete(ie);
202 }
203
204 FREESTRC(ie->cache_key);
205 FREESTRC(ie->file);
206 FREESTRC(ie->key);
207 ie->cache2 = NULL;
208
209 evas_common_rgba_image_scalecache_shutdown(ie);
210
211 free(ie);
212}
213
214static Image_Entry *
215_evas_cache_image_entry_new(Evas_Cache2 *cache,
216 const char *hkey,
217 Image_Timestamp *tstamp,
218 const char *file,
219 const char *key,
220 RGBA_Image_Loadopts *lo,
221 int *error)
222{
223 Image_Entry *ie;
224 RGBA_Image *im;
225
226 // ie = cache->func.alloc();
227 im = calloc(1, sizeof(RGBA_Image));
228 if (!im)
229 {
230 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
231 return NULL;
232 }
233
234 im->flags = RGBA_IMAGE_NOTHING;
235 im->ref = 1;
236 evas_common_rgba_image_scalecache_init(&im->cache_entry);
237
238 ie = &im->cache_entry;
239
240 ie->cache2 = cache;
241 if (hkey) ie->cache_key = eina_stringshare_add(hkey);
242 ie->flags.need_data = 1;
243 ie->space = EVAS_COLORSPACE_ARGB8888;
244 ie->w = -1;
245 ie->h = -1;
246 ie->scale = 1;
247 if (file) ie->file = eina_stringshare_add(file);
248 if (key) ie->key = eina_stringshare_add(key);
249 if (tstamp) ie->tstamp = *tstamp;
250 else memset(&ie->tstamp, 0, sizeof(Image_Timestamp));
251
252 if (lo) ie->load_opts = *lo;
253 if (ie->file)
254 {
255 if (!evas_cserve2_image_load(ie, ie->file, ie->key, &(ie->load_opts)))
256 {
257 ERR("couldn't load '%s' '%s' with cserve2!",
258 ie->file, ie->key ? ie->key : "");
259 _evas_cache_image_entry_delete(cache, ie);
260 return NULL;
261 }
262 }
263
264 if (ie->cache_key) _evas_cache_image_activ_add(ie);
265 else _evas_cache_image_dirty_add(ie);
266 return ie;
267}
268
269EAPI void
270evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h)
271{
272 Evas_Cache2 *cache = ie->cache2;
273 int wmin = w > 0 ? w : 1;
274 int hmin = h > 0 ? h : 1;
275
276 if (cache->func.surface_alloc(ie, wmin, hmin))
277 {
278 wmin = 0;
279 hmin = 0;
280 }
281
282 ie->w = wmin;
283 ie->h = hmin;
284 ie->allocated.w = wmin;
285 ie->allocated.h = hmin;
286 ie->flags.loaded = EINA_TRUE;
287}
288
289static void
290_evas_cache2_image_preloaded_cb(void *data, Eina_Bool success)
291{
292 Image_Entry *ie = data;
293 Evas_Cache_Target *tmp;
294
295 ie->cache2->preload = eina_list_remove(ie->cache2->preload, ie);
296 ie->flags.preload_done = success;
297
298 while ((tmp = ie->targets))
299 {
300 ie->targets = (Evas_Cache_Target *)
301 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
302 EINA_INLIST_GET(ie->targets));
303 if (!ie->flags.delete_me)
304 evas_object_inform_call_image_preloaded((Evas_Object *) tmp->target);
305 free(tmp);
306 }
307
308 if (ie->flags.delete_me)
309 _evas_cache_image_entry_delete(ie->cache2, ie);
310}
311
312static Eina_Bool
313_evas_cache2_image_entry_preload_add(Image_Entry *ie, const void *target)
314{
315 Evas_Cache_Target *tg;
316
317 if (ie->flags.preload_done)
318 return EINA_FALSE;
319
320 tg = malloc(sizeof(Evas_Cache_Target));
321 if (!tg)
322 return EINA_TRUE;
323
324 tg->target = target;
325 ie->targets = (Evas_Cache_Target *)
326 eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
327
328 if (!ie->preload_rid)
329 {
330 ie->cache2->preload = eina_list_append(ie->cache2->preload, ie);
331 evas_cserve2_image_preload(ie, _evas_cache2_image_preloaded_cb);
332 }
333
334 return EINA_TRUE;
335}
336
337static void
338_evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target)
339{
340 if (target)
341 {
342 Evas_Cache_Target *tg;
343
344 EINA_INLIST_FOREACH(ie->targets, tg)
345 {
346 if (tg->target == target)
347 {
348 ie->targets = (Evas_Cache_Target *)
349 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
350 EINA_INLIST_GET(tg));
351 free(tg);
352 break;
353 }
354 }
355 }
356 else
357 {
358 Evas_Cache_Target *tg;
359
360 while (ie->targets)
361 {
362 tg = ie->targets;
363 ie->targets = (Evas_Cache_Target *)
364 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
365 EINA_INLIST_GET(tg));
366 free(tg);
367 }
368 }
369
370 // FIXME: Should also send message to the server to cancel the request.
371}
372
373EAPI Image_Entry *
374evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
375{
376 Image_Entry *im;
377
378 if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
379 (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
380 (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
381 w &= ~0x1;
382
383 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
384 if (!im)
385 return NULL;
386
387 im->space = cspace;
388 im->flags.alpha = alpha;
389 evas_cache2_image_surface_alloc(im, w, h);
390 if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
391 {
392 _evas_cache_image_entry_delete(cache, im);
393 return NULL;
394 }
395
396 im->references = 1;
397 im->flags.loaded = EINA_TRUE;
398 if (cache->func.debug) cache->func.debug("copied-data", im);
399
400 return im;
401}
402
403EAPI Image_Entry *
404evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
405{
406 Image_Entry *im;
407
408 if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
409 (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
410 (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
411 w &= ~0x1;
412
413 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
414 if (!im) return NULL;
415 im->w = w;
416 im->h = h;
417 im->flags.alpha = alpha;
418 im->flags.loaded = 1;
419 if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
420 {
421 _evas_cache_image_entry_delete(cache, im);
422 return NULL;
423 }
424 im->references = 1;
425 if (cache->func.debug) cache->func.debug("data", im);
426 return im;
427}
428
429EAPI Image_Entry *
430evas_cache2_image_empty(Evas_Cache2 *cache)
431{
432 Image_Entry *im;
433
434 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
435 if (!im)
436 return NULL;
437
438 im->references = 1;
439 return im;
440}
441
442EAPI Image_Entry *
443evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h)
444{
445 Evas_Cache2 *cache;
446 Image_Entry *im2 = NULL;
447 int error;
448
449 if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
450 (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
451 (im->space == EVAS_COLORSPACE_YCBCR422601_PL))
452 w &= ~0x1;
453
454 if ((im->w == w) && (im->h == h)) return im;
455
456 cache = im->cache2;
457 im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL,
458 NULL);
459 if (!im2) goto on_error;
460
461 im2->flags.alpha = im->flags.alpha;
462 im2->space = im->space;
463 im2->load_opts = im->load_opts;
464 evas_cache2_image_surface_alloc(im2, w, h);
465 error = cache->func.size_set(im2, im, w, h);
466 if (error != 0) goto on_error;
467
468 im2->references = 1;
469
470 evas_cache2_image_close(im);
471 return im2;
472
473on_error:
474 if (im2)
475 _evas_cache_image_entry_delete(cache, im2);
476 return NULL;
477}
478
479EAPI Evas_Cache2 *
480evas_cache2_init(const Evas_Cache2_Image_Func *cb)
481{
482 Evas_Cache2 *cache = calloc(1, sizeof(Evas_Cache2));
483
484 cache->func = *cb;
485 cache->activ = eina_hash_string_superfast_new(NULL);
486 cache->inactiv = eina_hash_string_superfast_new(NULL);
487
488 return cache;
489}
490
491static Eina_Bool
492_evas_cache_image_free_cb(EINA_UNUSED const Eina_Hash *hash, EINA_UNUSED const void *key, void *data, void *fdata)
493{
494 Eina_List **delete_list = fdata;
495 *delete_list = eina_list_prepend(*delete_list, data);
496 return EINA_TRUE;
497}
498
499EAPI void
500evas_cache2_shutdown(Evas_Cache2 *cache)
501{
502 Eina_List *delete_list;
503 Image_Entry *im;
504
505 while (cache->lru)
506 {
507 im = (Image_Entry *)cache->lru;
508 _evas_cache_image_entry_delete(cache, im);
509 }
510 /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */
511 while (cache->dirty)
512 {
513 im = (Image_Entry *)cache->dirty;
514 _evas_cache_image_entry_delete(cache, im);
515 }
516
517 delete_list = NULL;
518 eina_hash_foreach(cache->activ, _evas_cache_image_free_cb, &delete_list);
519 while (delete_list)
520 {
521 _evas_cache_image_entry_delete(cache, eina_list_data_get(delete_list));
522 delete_list = eina_list_remove_list(delete_list, delete_list);
523 }
524
525 eina_hash_free(cache->activ);
526 eina_hash_free(cache->inactiv);
527
528 free(cache);
529}
530
531static void
532_create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, RGBA_Image_Loadopts *lo)
533{
534 const char *ckey = "(null)";
535 size_t size;
536
537 /* generate hkey from file+key+load opts */
538 memcpy(hkey, path, pathlen);
539 size = pathlen;
540 memcpy(hkey + size, "//://", 5);
541 size += 5;
542 if (key) ckey = key;
543 memcpy(hkey + size, ckey, keylen);
544 size += keylen;
545 if (lo)
546 {
547 memcpy(hkey + size, "//@/", 4);
548 size += 4;
549 size += eina_convert_xtoa(lo->scale_down_by, hkey + size);
550 hkey[size] = '/';
551 size += 1;
552 size += eina_convert_dtoa(lo->dpi, hkey + size);
553 hkey[size] = '/';
554 size += 1;
555 size += eina_convert_xtoa(lo->w, hkey + size);
556 hkey[size] = 'x';
557 size += 1;
558 size += eina_convert_xtoa(lo->h, hkey + size);
559 hkey[size] = '/';
560 size += 1;
561 size += eina_convert_xtoa(lo->region.x, hkey + size);
562 hkey[size] = '+';
563 size += 1;
564 size += eina_convert_xtoa(lo->region.y, hkey + size);
565 hkey[size] = '.';
566 size += 1;
567 size += eina_convert_xtoa(lo->region.w, hkey + size);
568 hkey[size] = 'x';
569 size += 1;
570 size += eina_convert_xtoa(lo->region.h, hkey + size);
571
572 if (lo->orientation)
573 {
574 hkey[size] = '/';
575 size += 1;
576 hkey[size] = 'o';
577 size += 1;
578 }
579 }
580 hkey[size] = '\0';
581}
582
583EAPI Image_Entry *
584evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, RGBA_Image_Loadopts *lo, int *error)
585{
586 size_t size;
587 size_t pathlen;
588 size_t keylen;
589 char *hkey;
590 Image_Entry *im;
591 int stat_done = 0, stat_failed = 0;
592 struct stat st;
593 Image_Timestamp tstamp;
594 Evas_Image_Load_Opts prevent = { 0, 0.0, 0, 0, 0, { 0, 0, 0, 0 }, EINA_FALSE };
595
596 if ((!path) || ((!path) && (!key)))
597 {
598 *error = EVAS_LOAD_ERROR_GENERIC;
599 return NULL;
600 }
601
602 pathlen = strlen(path);
603 keylen = key ? strlen(key) : 6;
604 size = pathlen + keylen + 132;
605 hkey = alloca(sizeof(char) * size);
606
607 _create_hash_key(hkey, path, pathlen, key, keylen, lo);
608 DBG("Looking at the hash for key '%s'", hkey);
609
610 /* use local var to copy default load options to the image entry */
611 if ((!lo) ||
612 (lo &&
613 (lo->scale_down_by == 0) &&
614 (lo->dpi == 0.0) &&
615 ((lo->w == 0) || (lo->h == 0)) &&
616 ((lo->region.w == 0) || (lo->region.h == 0)) &&
617 (lo->orientation == 0)
618 ))
619 {
620 lo = &prevent;
621 }
622
623 im = eina_hash_find(cache->activ, hkey);
624
625 if (im)
626 {
627 int ok = 1;
628 DBG("Found entry on active hash for key: '%s'", hkey);
629
630 stat_done = 1;
631 if (stat(path, &st) < 0)
632 {
633 stat_failed = 1;
634 ok = 0;
635 }
636 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
637 if (ok) goto on_ok;
638 /* image we found doesn't match what's on disk (stat info wise)
639 * so dirty the active cache entry so we never find it again. this
640 * also implicitly guarantees that we only have 1 active copy
641 * of an image at a given key. we wither find it and keep re-reffing
642 * it or we dirty it and get it out */
643 DBG("Entry on inactive hash was invalid (file changed or deleted).");
644 _evas_cache_image_dirty_add(im);
645 im = NULL;
646 }
647
648 im = eina_hash_find(cache->inactiv, hkey);
649
650 if (im)
651 {
652 int ok = 1;
653 DBG("Found entry on inactive hash for key: '%s'", hkey);
654
655 if (!stat_done)
656 {
657 stat_done = 1;
658 if (stat(path, &st) < 0)
659 {
660 stat_failed = 1;
661 ok = 0;
662 }
663 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
664 }
665 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
666
667 if (ok)
668 {
669 /* remove from lru and make it active again */
670 _evas_cache_image_lru_del(im);
671 _evas_cache_image_activ_add(im);
672 goto on_ok;
673 }
674 DBG("Entry on inactive hash was invalid (file changed or deleted).");
675 /* as avtive cache find - if we match in lru and its invalid, dirty */
676 _evas_cache_image_dirty_add(im);
677 /* this image never used, so it have to be deleted */
678 _evas_cache_image_entry_delete(cache, im);
679 im = NULL;
680 }
681 if (stat_failed) goto on_stat_error;
682
683 if (!stat_done)
684 {
685 if (stat(path, &st) < 0) goto on_stat_error;
686 }
687 _timestamp_build(&tstamp, &st);
688 DBG("Creating a new entry for key '%s'.", hkey);
689 im = _evas_cache_image_entry_new(cache, hkey, &tstamp, path, key,
690 lo, error);
691 if (!im) goto on_stat_error;
692
693on_ok:
694 *error = EVAS_LOAD_ERROR_NONE;
695 DBG("Using entry on hash for key '%s'", hkey);
696
697 im->references++;
698
699 return im;
700
701on_stat_error:
702#ifndef _WIN32
703 if ((errno == ENOENT) || (errno == ENOTDIR) ||
704 (errno == ENAMETOOLONG) || (errno == ELOOP))
705#else
706 if (errno == ENOENT)
707#endif
708 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
709#ifndef _WIN32
710 else if ((errno == ENOMEM) || (errno == EOVERFLOW))
711#else
712 else if (errno == ENOMEM)
713#endif
714 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
715 else if (errno == EACCES)
716 *error = EVAS_LOAD_ERROR_PERMISSION_DENIED;
717 else
718 *error = EVAS_LOAD_ERROR_GENERIC;
719
720 if (im) _evas_cache_image_entry_delete(cache, im);
721 return NULL;
722}
723
724EAPI int
725evas_cache2_image_open_wait(Image_Entry *im)
726{
727 DBG("Wait for open image '%s' '%s'", im->file, im->key);
728 if (evas_cserve2_image_load_wait(im) != CSERVE2_NONE)
729 return EVAS_LOAD_ERROR_GENERIC;
730
731 return EVAS_LOAD_ERROR_NONE;
732}
733
734EAPI void
735evas_cache2_image_close(Image_Entry *im)
736{
737 Evas_Cache2 *cache;
738 int references;
739
740 im->references--;
741 if (im->references < 0)
742 {
743 ERR("image with negative references: %d", im->references);
744 im->references = 0;
745 }
746
747 references = im->references;
748 cache = im->cache2;
749
750 if (references > 0)
751 return;
752
753 if (im->flags.dirty)
754 {
755 _evas_cache_image_entry_delete(cache, im);
756 return;
757 }
758
759 _evas_cache_image_lru_add(im);
760 if (cache)
761 evas_cache2_flush(cache);
762}
763
764EAPI int
765evas_cache2_image_load_data(Image_Entry *ie)
766{
767 int error = EVAS_LOAD_ERROR_NONE;
768
769 if ((ie->flags.loaded) && (!ie->flags.animated))
770 return error;
771
772 ie->flags.in_progress = EINA_TRUE;
773
774 DBG("try cserve2 image data '%s' '%s'",
775 ie->file, ie->key ? ie->key : "");
776 if (evas_cserve2_image_data_load(ie))
777 {
778 evas_cserve2_image_load_data_wait(ie);
779 RGBA_Image *im = (RGBA_Image *)ie;
780 DBG("try cserve2 image data '%s' '%s' loaded!",
781 ie->file, ie->key ? ie->key : "");
782 if (im->image.data)
783 {
784 error = EVAS_LOAD_ERROR_NONE;
785 }
786 else
787 {
788 ERR("Failed to load data for image '%s' '%s'.",
789 ie->file, ie->key ? ie->key : "");
790 error = EVAS_LOAD_ERROR_GENERIC;
791 }
792 }
793 else
794 {
795 ERR("Couldn't send LOAD message to cserve2.");
796 error = EVAS_LOAD_ERROR_GENERIC;
797 }
798
799 ie->flags.in_progress = EINA_FALSE;
800 ie->flags.loaded = 1;
801
802 if (error != EVAS_LOAD_ERROR_NONE)
803 ie->flags.loaded = 0;
804
805 return error;
806}
807
808EAPI void
809evas_cache2_image_unload_data(Image_Entry *im)
810{
811 // FIXME: This function seems pretty useless, since we always have
812 // to send an UNLOAD message to the server when closing an image,
813 // even if we didn't send a LOAD message before, because the SETOPTS
814 // message increases the image refcount.
815 if (im->flags.in_progress)
816 return;
817
818 if ((!im->file))
819 return;
820
821 if (!im->flags.loaded)
822 return;
823}
824
825EAPI void
826evas_cache2_image_preload_data(Image_Entry *im, const void *target)
827{
828 RGBA_Image *img = (RGBA_Image *)im;
829
830 if ((im->flags.loaded) && (img->image.data))
831 {
832 evas_object_inform_call_image_preloaded((Evas_Object *)target);
833 return;
834 }
835
836 if (!_evas_cache2_image_entry_preload_add(im, target))
837 evas_object_inform_call_image_preloaded((Evas_Object *)target);
838}
839
840EAPI void
841evas_cache2_image_preload_cancel(Image_Entry *im, const void *target)
842{
843 if (!target)
844 return;
845
846 _evas_cache2_image_entry_preload_remove(im, target);
847}
848
849EAPI DATA32 *
850evas_cache2_image_pixels(Image_Entry *im)
851{
852 return im->cache2->func.surface_pixels(im);
853}
854
855EAPI Image_Entry *
856evas_cache2_image_writable(Image_Entry *im)
857{
858 Evas_Cache2 *cache = im->cache2;
859 Image_Entry *im2 = NULL;
860
861 if (!im->cache_key)
862 {
863 if (!im->flags.dirty)
864 _evas_cache_image_dirty_add(im);
865 return im;
866 }
867
868 im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
869 evas_cache2_image_pixels(im),
870 im->flags.alpha, im->space);
871 if (!im2)
872 goto on_error;
873
874 evas_cache2_image_close(im);
875 return im2;
876
877on_error:
878 if (im2)
879 _evas_cache_image_entry_delete(cache, im2);
880 return NULL;
881}
882
883EAPI Image_Entry *
884evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
885{
886 Evas_Cache2 *cache = im->cache2;
887 Image_Entry *im2 = NULL;
888
889 if (!im->cache_key)
890 {
891 if (!im->flags.dirty)
892 _evas_cache_image_dirty_add(im);
893 im2 = im;
894 }
895 else
896 {
897 im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
898 evas_cache2_image_pixels(im),
899 im->flags.alpha, im->space);
900 if (!im2)
901 goto on_error;
902
903 evas_cache2_image_close(im);
904 }
905
906 if (cache->func.dirty_region)
907 cache->func.dirty_region(im2, x, y, w, h);
908
909 return im2;
910
911on_error:
912 if (im2)
913 _evas_cache_image_entry_delete(cache, im2);
914 evas_cache2_image_close(im);
915 return NULL;
916}
917
918EAPI int
919evas_cache2_flush(Evas_Cache2 *cache)
920{
921 if (cache->limit == -1) return -1;
922
923 while ((cache->lru) && (cache->limit < cache->usage))
924 {
925 Image_Entry *im;
926
927 im = (Image_Entry *)cache->lru->last;
928 DBG("Remove unused entry from cache.");
929 _evas_cache_image_entry_delete(cache, im);
930 }
931
932 return cache->usage;
933}
934
935EAPI void
936evas_cache2_limit_set(Evas_Cache2 *cache, int limit)
937{
938 if (cache->limit == limit)
939 return;
940
941 DBG("Cache2 limit set to %d", limit);
942
943 cache->limit = limit;
944
945 evas_cache2_flush(cache);
946}
947
948EAPI int
949evas_cache2_limit_get(Evas_Cache2 *cache)
950{
951 return cache->limit;
952}
953
954EAPI int
955evas_cache2_usage_get(Evas_Cache2 *cache)
956{
957 return cache->usage;
958}
diff --git a/src/lib/evas/cache2/evas_cache2.h b/src/lib/evas/cache2/evas_cache2.h
new file mode 100644
index 0000000000..7028338e7b
--- /dev/null
+++ b/src/lib/evas/cache2/evas_cache2.h
@@ -0,0 +1,87 @@
1#ifndef _EVAS_CACHE2_H
2#define _EVAS_CACHE2_H
3
4typedef struct _Evas_Cache2_Image_Func Evas_Cache2_Image_Func;
5typedef struct _Evas_Cache2 Evas_Cache2;
6
7struct _Evas_Cache2_Image_Func
8{
9 // Image_Entry *(*alloc)(void);
10 // void (*dealloc)(Image_Entry *im);
11
12 /* The cache provide some helpers for surface manipulation. */
13 int (*surface_alloc)(Image_Entry *im, unsigned int w, unsigned int h);
14 void (*surface_delete)(Image_Entry *im);
15 DATA32 *(*surface_pixels)(Image_Entry *im);
16
17 /* The cache is doing the allocation and deallocation, you must just do the rest. */
18 // int (*constructor)(Image_Entry *im); /**< return is EVAS_LOAD_ERROR_* or EVAS_LOAD_ERROR_NONE! */
19 // void (*destructor)(Image_Entry *im);
20
21 void (*dirty_region)(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
22 /* Only called when references > 0. Need to provide a fresh copie of im. */
23 /* The destination surface does have a surface, but no allocated pixel data. */
24 int (*dirty)(Image_Entry *dst, const Image_Entry *src);
25 /* Only called when references == 1. We will call drop on `im'. */
26 /* The destination surface does not have any surface. */
27 int (*size_set)(Image_Entry *dst, const Image_Entry *src, unsigned int w, unsigned int h);
28
29 /* The destination surface does not have any surface. */
30 int (*copied_data)(Image_Entry *dst, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace);
31 /* The destination surface does not have any surface. */
32 int (*data)(Image_Entry *dst, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace);
33 int (*color_space)(Image_Entry *dst, int cspace);
34
35 /* This function need to update im->w and im->h. */
36 // int (*load)(Image_Entry *im); /**< return is EVAS_LOAD_ERROR_* or EVAS_LOAD_ERROR_NONE! */
37 int (*mem_size_get)(Image_Entry *im);
38 void (*debug)(const char *context, Image_Entry *im);
39};
40
41struct _Evas_Cache2
42{
43 Evas_Cache2_Image_Func func;
44
45 Eina_List *preload;
46
47 Eina_Hash *inactiv;
48 Eina_Hash *activ;
49 Eina_Inlist *dirty;
50 Eina_Inlist *lru;
51 int usage;
52 int limit;
53};
54
55#ifdef __cplusplus
56extern "C" {
57#endif
58
59EAPI Evas_Cache2* evas_cache2_init(const Evas_Cache2_Image_Func *cb);
60EAPI void evas_cache2_shutdown(Evas_Cache2 *cache);
61EAPI Image_Entry * evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, RGBA_Image_Loadopts *lo, int *error);
62EAPI int evas_cache2_image_open_wait(Image_Entry *im);
63EAPI void evas_cache2_image_close(Image_Entry *im);
64EAPI int evas_cache2_image_load_data(Image_Entry *ie);
65EAPI void evas_cache2_image_unload_data(Image_Entry *im);
66EAPI void evas_cache2_image_preload_data(Image_Entry *im, const void *target);
67
68EAPI DATA32 * evas_cache2_image_pixels(Image_Entry *im);
69EAPI Image_Entry * evas_cache2_image_writable(Image_Entry *im);
70EAPI Image_Entry * evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace);
71EAPI Image_Entry * evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace);
72EAPI Image_Entry * evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h);
73EAPI Image_Entry * evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
74EAPI Image_Entry * evas_cache2_image_empty(Evas_Cache2 *cache);
75EAPI void evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h);
76
77EAPI int evas_cache2_flush(Evas_Cache2 *cache);
78EAPI void evas_cache2_limit_set(Evas_Cache2 *cache, int limit);
79EAPI int evas_cache2_limit_get(Evas_Cache2 *cache);
80EAPI int evas_cache2_usage_get(Evas_Cache2 *cache);
81
82#ifdef __cplusplus
83}
84#endif
85
86
87#endif /* _EVAS_CACHE2_H */