15 #include "evas_common.h"
16 #include "evas_private.h"
17 #include "evas_cache2.h"
19 #include "evas_cs2_private.h"
21 #define FREESTRC(Var) \
24 eina_stringshare_del(Var); \
28 static void _evas_cache_image_dirty_add(Image_Entry *im);
29 static void _evas_cache_image_dirty_del(Image_Entry *im);
30 static void _evas_cache_image_activ_add(Image_Entry *im);
31 static void _evas_cache_image_activ_del(Image_Entry *im);
32 static void _evas_cache_image_lru_add(Image_Entry *im);
33 static void _evas_cache_image_lru_del(Image_Entry *im);
34 static 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);
39 _evas_cache_image_dirty_add(Image_Entry *im)
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);
47 im->cache2->dirty = eina_inlist_prepend(im->cache2->dirty, EINA_INLIST_GET(im));
50 eina_stringshare_del(im->cache_key);
56 _evas_cache_image_dirty_del(Image_Entry *im)
58 if (!im->flags.dirty) return;
59 if (!im->cache2) return;
62 im->cache2->dirty = eina_inlist_remove(im->cache2->dirty, EINA_INLIST_GET(im));
66 _evas_cache_image_activ_add(Image_Entry *im)
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;
75 eina_hash_direct_add(im->cache2->activ, im->cache_key, im);
79 _evas_cache_image_activ_del(Image_Entry *im)
81 if (!im->flags.activ) return;
82 if (!im->cache_key) return;
85 eina_hash_del(im->cache2->activ, im->cache_key, im);
89 _evas_cache_image_lru_add(Image_Entry *im)
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;
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);
104 _evas_cache_image_lru_del(Image_Entry *im)
106 if (!im->flags.lru) return;
107 if (!im->cache_key) return;
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);
117 _evas_cache_image_lru_nodata_add(Image_Entry *im)
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);
124 im->flags.cached = 1;
125 im->cache2->lru_nodata = eina_inlist_prepend(im->cache2->lru_nodata, EINA_INLIST_GET(im));
129 _evas_cache_image_lru_nodata_del(Image_Entry *im)
131 if (!im->flags.lru_nodata) return;
133 im->flags.cached = 0;
134 im->cache2->lru_nodata = eina_inlist_remove(im->cache2->lru_nodata, EINA_INLIST_GET(im));
139 _timestamp_compare(Image_Timestamp *tstamp, struct stat *st)
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)
149 if (tstamp->mtime_nsec != (unsigned long int)st->st_mtimensec)
157 _timestamp_build(Image_Timestamp *tstamp, struct stat *st)
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;
166 tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec;
172 _evas_cache_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie)
176 if (ie->flags.delete_me == 1)
181 ie->flags.delete_me = 1;
182 _evas_cache2_image_entry_preload_remove(ie, NULL);
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);
194 evas_cserve2_image_unload(ie);
195 evas_cache2_image_unload_data(ie);
196 evas_cserve2_image_free(ie);
201 cache->func.surface_delete(ie);
204 FREESTRC(ie->cache_key);
209 evas_common_rgba_image_scalecache_shutdown(ie);
215 _evas_cache_image_entry_new(Evas_Cache2 *cache,
217 Image_Timestamp *tstamp,
220 RGBA_Image_Loadopts *lo,
226 // ie = cache->func.alloc();
227 im = calloc(1, sizeof(RGBA_Image));
230 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
234 im->flags = RGBA_IMAGE_NOTHING;
236 evas_common_rgba_image_scalecache_init(&im->cache_entry);
238 ie = &im->cache_entry;
241 if (hkey) ie->cache_key = eina_stringshare_add(hkey);
242 ie->flags.need_data = 1;
243 ie->space = EVAS_COLORSPACE_ARGB8888;
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));
252 if (lo) ie->load_opts = *lo;
255 if (!evas_cserve2_image_load(ie, ie->file, ie->key, &(ie->load_opts)))
257 ERR("couldn't load '%s' '%s' with cserve2!",
258 ie->file, ie->key ? ie->key : "");
259 _evas_cache_image_entry_delete(cache, ie);
264 if (ie->cache_key) _evas_cache_image_activ_add(ie);
265 else _evas_cache_image_dirty_add(ie);
270 evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h)
272 Evas_Cache2 *cache = ie->cache2;
273 int wmin = w > 0 ? w : 1;
274 int hmin = h > 0 ? h : 1;
276 if (cache->func.surface_alloc(ie, wmin, hmin))
284 ie->allocated.w = wmin;
285 ie->allocated.h = hmin;
286 ie->flags.loaded = EINA_TRUE;
290 _evas_cache2_image_preloaded_cb(void *data, Eina_Bool success)
292 Image_Entry *ie = data;
293 Evas_Cache_Target *tmp;
295 ie->cache2->preload = eina_list_remove(ie->cache2->preload, ie);
296 ie->flags.preload_done = success;
298 while ((tmp = ie->targets))
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);
308 if (ie->flags.delete_me)
309 _evas_cache_image_entry_delete(ie->cache2, ie);
313 _evas_cache2_image_entry_preload_add(Image_Entry *ie, const void *target)
315 Evas_Cache_Target *tg;
317 if (ie->flags.preload_done)
320 tg = malloc(sizeof(Evas_Cache_Target));
325 ie->targets = (Evas_Cache_Target *)
326 eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
328 if (!ie->preload_rid)
330 ie->cache2->preload = eina_list_append(ie->cache2->preload, ie);
331 evas_cserve2_image_preload(ie, _evas_cache2_image_preloaded_cb);
338 _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target)
342 Evas_Cache_Target *tg;
344 EINA_INLIST_FOREACH(ie->targets, tg)
346 if (tg->target == target)
348 ie->targets = (Evas_Cache_Target *)
349 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
350 EINA_INLIST_GET(tg));
358 Evas_Cache_Target *tg;
363 ie->targets = (Evas_Cache_Target *)
364 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
365 EINA_INLIST_GET(tg));
370 // FIXME: Should also send message to the server to cancel the request.
374 evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
378 if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
379 (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
380 (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
383 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
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)
392 _evas_cache_image_entry_delete(cache, im);
397 im->flags.loaded = EINA_TRUE;
398 if (cache->func.debug) cache->func.debug("copied-data", im);
404 evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
408 if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
409 (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
410 (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
413 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
414 if (!im) return NULL;
417 im->flags.alpha = alpha;
418 im->flags.loaded = 1;
419 if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
421 _evas_cache_image_entry_delete(cache, im);
425 if (cache->func.debug) cache->func.debug("data", im);
430 evas_cache2_image_empty(Evas_Cache2 *cache)
434 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
443 evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h)
446 Image_Entry *im2 = NULL;
449 if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
450 (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
451 (im->space == EVAS_COLORSPACE_YCBCR422601_PL))
454 if ((im->w == w) && (im->h == h)) return im;
457 im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL,
459 if (!im2) goto on_error;
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;
470 evas_cache2_image_close(im);
475 _evas_cache_image_entry_delete(cache, im2);
480 evas_cache2_init(const Evas_Cache2_Image_Func *cb)
482 Evas_Cache2 *cache = calloc(1, sizeof(Evas_Cache2));
485 cache->activ = eina_hash_string_superfast_new(NULL);
486 cache->inactiv = eina_hash_string_superfast_new(NULL);
492 _evas_cache_image_free_cb(__UNUSED__ const Eina_Hash *hash, __UNUSED__ const void *key, void *data, void *fdata)
494 Eina_List **delete_list = fdata;
495 *delete_list = eina_list_prepend(*delete_list, data);
500 evas_cache2_shutdown(Evas_Cache2 *cache)
502 Eina_List *delete_list;
507 im = (Image_Entry *)cache->lru;
508 _evas_cache_image_entry_delete(cache, im);
510 /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */
513 im = (Image_Entry *)cache->dirty;
514 _evas_cache_image_entry_delete(cache, im);
518 eina_hash_foreach(cache->activ, _evas_cache_image_free_cb, &delete_list);
521 _evas_cache_image_entry_delete(cache, eina_list_data_get(delete_list));
522 delete_list = eina_list_remove_list(delete_list, delete_list);
525 eina_hash_free(cache->activ);
526 eina_hash_free(cache->inactiv);
532 _create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, RGBA_Image_Loadopts *lo)
534 const char *ckey = "(null)";
537 /* generate hkey from file+key+load opts */
538 memcpy(hkey, path, pathlen);
540 memcpy(hkey + size, "//://", 5);
543 memcpy(hkey + size, ckey, keylen);
547 memcpy(hkey + size, "//@/", 4);
549 size += eina_convert_xtoa(lo->scale_down_by, hkey + size);
552 size += eina_convert_dtoa(lo->dpi, hkey + size);
555 size += eina_convert_xtoa(lo->w, hkey + size);
558 size += eina_convert_xtoa(lo->h, hkey + size);
561 size += eina_convert_xtoa(lo->region.x, hkey + size);
564 size += eina_convert_xtoa(lo->region.y, hkey + size);
567 size += eina_convert_xtoa(lo->region.w, hkey + size);
570 size += eina_convert_xtoa(lo->region.h, hkey + size);
584 evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, RGBA_Image_Loadopts *lo, int *error)
591 int stat_done = 0, stat_failed = 0;
593 Image_Timestamp tstamp;
594 Evas_Image_Load_Opts prevent = { 0, 0.0, 0, 0, 0, { 0, 0, 0, 0 }, EINA_FALSE };
596 if ((!path) || ((!path) && (!key)))
598 *error = EVAS_LOAD_ERROR_GENERIC;
602 pathlen = strlen(path);
603 keylen = key ? strlen(key) : 6;
604 size = pathlen + keylen + 132;
605 hkey = alloca(sizeof(char) * size);
607 _create_hash_key(hkey, path, pathlen, key, keylen, lo);
608 DBG("Looking at the hash for key '%s'", hkey);
610 /* use local var to copy default load options to the image entry */
613 (lo->scale_down_by == 0) &&
615 ((lo->w == 0) || (lo->h == 0)) &&
616 ((lo->region.w == 0) || (lo->region.h == 0)) &&
617 (lo->orientation == 0)
623 im = eina_hash_find(cache->activ, hkey);
628 DBG("Found entry on active hash for key: '%s'", hkey);
631 if (stat(path, &st) < 0)
636 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
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);
648 im = eina_hash_find(cache->inactiv, hkey);
653 DBG("Found entry on inactive hash for key: '%s'", hkey);
658 if (stat(path, &st) < 0)
663 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
665 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
669 /* remove from lru and make it active again */
670 _evas_cache_image_lru_del(im);
671 _evas_cache_image_activ_add(im);
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);
681 if (stat_failed) goto on_stat_error;
685 if (stat(path, &st) < 0) goto on_stat_error;
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,
691 if (!im) goto on_stat_error;
694 *error = EVAS_LOAD_ERROR_NONE;
695 DBG("Using entry on hash for key '%s'", hkey);
703 if ((errno == ENOENT) || (errno == ENOTDIR) ||
704 (errno == ENAMETOOLONG) || (errno == ELOOP))
708 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
710 else if ((errno == ENOMEM) || (errno == EOVERFLOW))
712 else if (errno == ENOMEM)
714 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
715 else if (errno == EACCES)
716 *error = EVAS_LOAD_ERROR_PERMISSION_DENIED;
718 *error = EVAS_LOAD_ERROR_GENERIC;
720 if (im) _evas_cache_image_entry_delete(cache, im);
725 evas_cache2_image_open_wait(Image_Entry *im)
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;
731 return EVAS_LOAD_ERROR_NONE;
735 evas_cache2_image_close(Image_Entry *im)
741 if (im->references < 0)
743 ERR("image with negative references: %d", im->references);
747 references = im->references;
755 _evas_cache_image_entry_delete(cache, im);
759 _evas_cache_image_lru_add(im);
761 evas_cache2_flush(cache);
765 evas_cache2_image_load_data(Image_Entry *ie)
767 int error = EVAS_LOAD_ERROR_NONE;
769 if ((ie->flags.loaded) && (!ie->flags.animated))
772 ie->flags.in_progress = EINA_TRUE;
774 DBG("try cserve2 image data '%s' '%s'",
775 ie->file, ie->key ? ie->key : "");
776 if (evas_cserve2_image_data_load(ie))
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 : "");
784 error = EVAS_LOAD_ERROR_NONE;
788 ERR("Failed to load data for image '%s' '%s'.",
789 ie->file, ie->key ? ie->key : "");
790 error = EVAS_LOAD_ERROR_GENERIC;
795 ERR("Couldn't send LOAD message to cserve2.");
796 error = EVAS_LOAD_ERROR_GENERIC;
799 ie->flags.in_progress = EINA_FALSE;
800 ie->flags.loaded = 1;
802 if (error != EVAS_LOAD_ERROR_NONE)
803 ie->flags.loaded = 0;
809 evas_cache2_image_unload_data(Image_Entry *im)
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)
821 if (!im->flags.loaded)
825 im->flags.loaded = 0;
829 evas_cache2_image_preload_data(Image_Entry *im, const void *target)
831 RGBA_Image *img = (RGBA_Image *)im;
833 if ((im->flags.loaded) && (img->image.data))
835 evas_object_inform_call_image_preloaded((Evas_Object *)target);
839 if (!_evas_cache2_image_entry_preload_add(im, target))
840 evas_object_inform_call_image_preloaded((Evas_Object *)target);
844 evas_cache2_image_preload_cancel(Image_Entry *im, const void *target)
849 _evas_cache2_image_entry_preload_remove(im, target);
853 evas_cache2_image_pixels(Image_Entry *im)
855 return im->cache2->func.surface_pixels(im);
859 evas_cache2_image_writable(Image_Entry *im)
861 Evas_Cache2 *cache = im->cache2;
862 Image_Entry *im2 = NULL;
866 if (!im->flags.dirty)
867 _evas_cache_image_dirty_add(im);
871 im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
872 evas_cache2_image_pixels(im),
873 im->flags.alpha, im->space);
877 evas_cache2_image_close(im);
882 _evas_cache_image_entry_delete(cache, im2);
887 evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
889 Evas_Cache2 *cache = im->cache2;
890 Image_Entry *im2 = NULL;
894 if (!im->flags.dirty)
895 _evas_cache_image_dirty_add(im);
900 im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
901 evas_cache2_image_pixels(im),
902 im->flags.alpha, im->space);
906 evas_cache2_image_close(im);
909 if (cache->func.dirty_region)
910 cache->func.dirty_region(im2, x, y, w, h);
916 _evas_cache_image_entry_delete(cache, im2);
917 evas_cache2_image_close(im);
922 evas_cache2_flush(Evas_Cache2 *cache)
924 if (cache->limit == -1) return -1;
926 while ((cache->lru) && (cache->limit < cache->usage))
930 im = (Image_Entry *)cache->lru->last;
931 DBG("Remove unused entry from cache.");
932 _evas_cache_image_entry_delete(cache, im);
939 evas_cache2_limit_set(Evas_Cache2 *cache, int limit)
941 if (cache->limit == limit)
944 DBG("Cache2 limit set to %d", limit);
946 cache->limit = limit;
948 evas_cache2_flush(cache);
952 evas_cache2_limit_get(Evas_Cache2 *cache)
958 evas_cache2_usage_get(Evas_Cache2 *cache)