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 #include "evas_common_private.h"
12 #include "evas_private.h"
13 
14 //#define CACHEDUMP 1
15 
16 typedef struct _Evas_Cache_Preload Evas_Cache_Preload;
17 
18 struct _Evas_Cache_Preload
19 {
20    EINA_INLIST;
21    Image_Entry *ie;
22 };
23 
24 static SLK(engine_lock);
25 static int _evas_cache_mutex_init = 0;
26 
27 static void _evas_cache_image_entry_preload_remove(Image_Entry *ie, const Eo *target, Eina_Bool force);
28 
29 #define FREESTRC(Var)             \
30    if (Var)                       \
31 {                              \
32    eina_stringshare_del(Var);  \
33    Var = NULL;                 \
34 }
35 
36 static void _evas_cache_image_dirty_add(Image_Entry *im);
37 static void _evas_cache_image_dirty_del(Image_Entry *im);
38 static void _evas_cache_image_activ_add(Image_Entry *im);
39 static void _evas_cache_image_activ_del(Image_Entry *im);
40 static void _evas_cache_image_lru_add(Image_Entry *im);
41 static void _evas_cache_image_lru_del(Image_Entry *im);
42 static void _evas_cache_image_lru_nodata_add(Image_Entry *im);
43 static void _evas_cache_image_lru_nodata_del(Image_Entry *im);
44 
45 static void
_evas_cache_image_dirty_add(Image_Entry * im)46 _evas_cache_image_dirty_add(Image_Entry *im)
47 {
48    if (im->flags.dirty) return;
49    if (!im->cache) return;
50    _evas_cache_image_activ_del(im);
51    _evas_cache_image_lru_del(im);
52    _evas_cache_image_lru_nodata_del(im);
53    im->flags.dirty = 1;
54    im->flags.cached = 1;
55    im->cache->dirty = eina_inlist_prepend(im->cache->dirty, EINA_INLIST_GET(im));
56    if (im->cache_key)
57      {
58         eina_stringshare_del(im->cache_key);
59         im->cache_key = NULL;
60      }
61 }
62 
63 static void
_evas_cache_image_dirty_del(Image_Entry * im)64 _evas_cache_image_dirty_del(Image_Entry *im)
65 {
66    if (!im->flags.dirty) return;
67    if (!im->cache) return;
68    im->flags.dirty = 0;
69    im->flags.cached = 0;
70    im->cache->dirty = eina_inlist_remove(im->cache->dirty, EINA_INLIST_GET(im));
71 }
72 
73 static void
_evas_cache_image_activ_add(Image_Entry * im)74 _evas_cache_image_activ_add(Image_Entry *im)
75 {
76    if (im->flags.activ) return;
77    if (!im->cache) return;
78    _evas_cache_image_dirty_del(im);
79    _evas_cache_image_lru_del(im);
80    _evas_cache_image_lru_nodata_del(im);
81    if (!im->cache_key) return;
82    im->flags.activ = 1;
83    im->flags.cached = 1;
84    if (im->flags.given_mmap)
85      eina_hash_direct_add(im->cache->mmap_activ, im->cache_key, im);
86    else
87      eina_hash_direct_add(im->cache->activ, im->cache_key, im);
88 }
89 
90 static void
_evas_cache_image_activ_del(Image_Entry * im)91 _evas_cache_image_activ_del(Image_Entry *im)
92 {
93    if (!im->flags.activ) return;
94    if (!im->cache_key) return;
95    if (!im->cache) return;
96    im->flags.activ = 0;
97    im->flags.cached = 0;
98    if (im->flags.given_mmap)
99      eina_hash_del(im->cache->mmap_activ, im->cache_key, im);
100    else
101      eina_hash_del(im->cache->activ, im->cache_key, im);
102 }
103 
104 static void
_evas_cache_image_lru_add(Image_Entry * im)105 _evas_cache_image_lru_add(Image_Entry *im)
106 {
107    if (im->flags.lru) return;
108    if (!im->cache) return;
109    _evas_cache_image_dirty_del(im);
110    _evas_cache_image_activ_del(im);
111    _evas_cache_image_lru_nodata_del(im);
112    if (!im->cache_key) return;
113    im->flags.lru = 1;
114    im->flags.cached = 1;
115    if (im->flags.given_mmap)
116      eina_hash_direct_add(im->cache->mmap_inactiv, im->cache_key, im);
117    else
118      eina_hash_direct_add(im->cache->inactiv, im->cache_key, im);
119    im->cache->lru = eina_inlist_prepend(im->cache->lru, EINA_INLIST_GET(im));
120    im->cache->usage += im->cache->func.mem_size_get(im);
121 }
122 
123 static void
_evas_cache_image_lru_del(Image_Entry * im)124 _evas_cache_image_lru_del(Image_Entry *im)
125 {
126    if (!im->flags.lru) return;
127    if (!im->cache_key) return;
128    if (!im->cache) return;
129    im->flags.lru = 0;
130    im->flags.cached = 0;
131    if (im->flags.given_mmap)
132      eina_hash_del(im->cache->mmap_inactiv, im->cache_key, im);
133    else
134      eina_hash_del(im->cache->inactiv, im->cache_key, im);
135    im->cache->lru = eina_inlist_remove(im->cache->lru, EINA_INLIST_GET(im));
136    im->cache->usage -= im->cache->func.mem_size_get(im);
137 }
138 
139 static void
_evas_cache_image_lru_nodata_add(Image_Entry * im)140 _evas_cache_image_lru_nodata_add(Image_Entry *im)
141 {
142    if (im->flags.lru_nodata) return;
143    if (!im->cache) return;
144    _evas_cache_image_dirty_del(im);
145    _evas_cache_image_activ_del(im);
146    _evas_cache_image_lru_del(im);
147    im->flags.lru = 1;
148    im->flags.cached = 1;
149    im->cache->lru_nodata = eina_inlist_prepend(im->cache->lru_nodata, EINA_INLIST_GET(im));
150 }
151 
152 static void
_evas_cache_image_lru_nodata_del(Image_Entry * im)153 _evas_cache_image_lru_nodata_del(Image_Entry *im)
154 {
155    if (!im->flags.lru_nodata) return;
156    if (!im->cache) return;
157    im->flags.lru = 0;
158    im->flags.cached = 0;
159    im->cache->lru_nodata = eina_inlist_remove(im->cache->lru_nodata, EINA_INLIST_GET(im));
160 }
161 
162 static void
_evas_cache_image_entry_delete(Evas_Cache_Image * cache,Image_Entry * ie)163 _evas_cache_image_entry_delete(Evas_Cache_Image *cache, Image_Entry *ie)
164 {
165    if (!ie) return;
166    if (!ie->cache) return;
167    if ((cache) && (cache->func.debug)) cache->func.debug("deleting", ie);
168    if (ie->flags.delete_me == 1) return;
169    if (ie->preload)
170      {
171         ie->flags.delete_me = 1;
172         _evas_cache_image_entry_preload_remove(ie, NULL, EINA_TRUE);
173         return;
174      }
175    _evas_cache_image_dirty_del(ie);
176    _evas_cache_image_activ_del(ie);
177    _evas_cache_image_lru_del(ie);
178    _evas_cache_image_lru_nodata_del(ie);
179 
180    if ((cache) && (cache->func.destructor)) cache->func.destructor(ie);
181    FREESTRC(ie->cache_key);
182    FREESTRC(ie->file);
183    FREESTRC(ie->key);
184    if (ie->f && ie->flags.given_mmap)
185      {
186         eina_file_close(ie->f); // close matching open (in _evas_cache_image_entry_new) OK
187         ie->f = NULL;
188      }
189    ie->cache = NULL;
190    if ((cache) && (cache->func.surface_delete)) cache->func.surface_delete(ie);
191 
192    SLKD(ie->lock);
193    SLKD(ie->lock_cancel);
194    if ((cache) && (cache->func.dealloc)) cache->func.dealloc(ie);
195 }
196 
197 static Eina_Bool
_timestamp_compare(Image_Timestamp * tstamp,struct stat * st)198 _timestamp_compare(Image_Timestamp *tstamp, struct stat *st)
199 {
200    if (tstamp->mtime != st->st_mtime) return EINA_FALSE;
201    if (tstamp->size != st->st_size) return EINA_FALSE;
202    if (tstamp->ino != st->st_ino) return EINA_FALSE;
203 #ifdef _STAT_VER_LINUX
204 #if (defined __USE_MISC && defined st_mtime)
205    if (tstamp->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec)
206      return EINA_FALSE;
207 #else
208    if (tstamp->mtime_nsec != (unsigned long int)st->st_mtimensec)
209      return EINA_FALSE;
210 #endif
211 #endif
212    return EINA_TRUE;
213 }
214 
215 static void
_timestamp_build(Image_Timestamp * tstamp,struct stat * st)216 _timestamp_build(Image_Timestamp *tstamp, struct stat *st)
217 {
218    tstamp->mtime = st->st_mtime;
219    tstamp->size = st->st_size;
220    tstamp->ino = st->st_ino;
221 #ifdef _STAT_VER_LINUX
222 #if (defined __USE_MISC && defined st_mtime)
223    tstamp->mtime_nsec = (unsigned long int)st->st_mtim.tv_nsec;
224 #else
225    tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec;
226 #endif
227 #endif
228 }
229 
230 static Image_Entry *
_evas_cache_image_entry_new(Evas_Cache_Image * cache,const char * hkey,Image_Timestamp * tstamp,Eina_File * f,const char * file,const char * key,Evas_Image_Load_Opts * lo,int * error)231 _evas_cache_image_entry_new(Evas_Cache_Image *cache,
232                             const char *hkey,
233                             Image_Timestamp *tstamp,
234                             Eina_File *f,
235                             const char *file,
236                             const char *key,
237                             Evas_Image_Load_Opts *lo,
238                             int *error)
239 {
240    Image_Entry  *ie;
241 
242    if (!cache)
243      {
244         *error = EVAS_LOAD_ERROR_GENERIC;
245         return NULL;
246      }
247 
248    ie = cache->func.alloc();
249    if (!ie)
250      {
251         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
252         return NULL;
253      }
254    ie->cache = cache;
255    if (hkey) ie->cache_key = eina_stringshare_add(hkey);
256    ie->flags.need_data = 1;
257    ie->space = EVAS_COLORSPACE_ARGB8888;
258    ie->w = -1;
259    ie->h = -1;
260    ie->scale = 1;
261    ie->f = eina_file_dup(f);
262    ie->loader_data = NULL;
263    if (ie->f) ie->flags.given_mmap = EINA_TRUE;
264    if (file) ie->file = eina_stringshare_add(file);
265    if (key) ie->key = eina_stringshare_add(key);
266    if (tstamp) ie->tstamp = *tstamp;
267    else memset(&ie->tstamp, 0, sizeof(Image_Timestamp));
268 
269    SLKI(ie->lock);
270    SLKI(ie->lock_cancel);
271 
272    if (lo)
273      {
274         ie->load_opts = *lo;
275      }
276    if (ie->file || ie->f)
277      {
278         *error = cache->func.constructor(ie);
279         if (*error != EVAS_LOAD_ERROR_NONE)
280           {
281              _evas_cache_image_entry_delete(cache, ie);
282              return NULL;
283           }
284      }
285    if (cache->func.debug) cache->func.debug("build", ie);
286    if (ie->cache_key) _evas_cache_image_activ_add(ie);
287    else _evas_cache_image_dirty_add(ie);
288    return ie;
289 }
290 
291 static void
_evas_cache_image_entry_surface_alloc__locked(Evas_Cache_Image * cache,Image_Entry * ie,unsigned int wmin,unsigned int hmin)292 _evas_cache_image_entry_surface_alloc__locked(Evas_Cache_Image *cache,
293                                               Image_Entry *ie,
294                                               unsigned int wmin,
295                                               unsigned int hmin)
296 {
297    if ((ie->allocated.w == wmin) && (ie->allocated.h == hmin)) return;
298    if ((cache->func.surface_alloc(ie, wmin, hmin)) || (ie->load_failed))
299      {
300         wmin = 0;
301         hmin = 0;
302      }
303    ie->w = wmin;
304    ie->h = hmin;
305 }
306 
307 static void
_evas_cache_image_entry_surface_alloc(Evas_Cache_Image * cache,Image_Entry * ie,int w,int h)308 _evas_cache_image_entry_surface_alloc(Evas_Cache_Image *cache,
309                                       Image_Entry *ie, int w, int h)
310 {
311    int wmin = w > 0 ? w : 1;
312    int hmin = h > 0 ? h : 1;
313    SLKL(engine_lock);
314    _evas_cache_image_entry_surface_alloc__locked(cache, ie, wmin, hmin);
315    SLKU(engine_lock);
316 }
317 
318 static Eina_Bool
evas_cache_image_cancelled(void * data)319 evas_cache_image_cancelled(void *data)
320 {
321    Image_Entry *current = data;
322    Eina_Bool ret;
323 
324    evas_cache_image_ref(current);
325    ret = evas_preload_thread_cancelled_is(current->preload);
326    evas_cache_image_drop(current);
327    return ret;
328 }
329 
330 static void
_evas_cache_image_async_heavy(void * data)331 _evas_cache_image_async_heavy(void *data)
332 {
333    Evas_Cache_Image *cache;
334    Image_Entry *current;
335    int error;
336    int pchannel;
337 
338    eina_thread_name_set(eina_thread_self(), "Evas-preload");
339 
340    current = data;
341 
342    if (!current->cache) return;
343    SLKL(current->lock);
344    pchannel = current->channel;
345    current->channel++;
346    cache = current->cache;
347 
348    if ((!current->flags.loaded) &&
349        (current->info.loader) &&
350        (current->info.loader->threadable))
351      {
352         evas_module_task_register(evas_cache_image_cancelled, current);
353         error = cache->func.load(current);
354         evas_module_task_unregister();
355 
356         if (cache->func.debug) cache->func.debug("load", current);
357         current->load_error = error;
358         if (error != EVAS_LOAD_ERROR_NONE)
359           {
360              current->flags.loaded = 0;
361              _evas_cache_image_entry_surface_alloc(cache, current,
362                                                    current->w, current->h);
363           }
364      }
365    current->channel = pchannel;
366    // check the unload cancel flag
367    SLKL(current->lock_cancel);
368    if (current->flags.unload_cancel)
369      {
370         current->flags.unload_cancel = EINA_FALSE;
371         cache->func.surface_delete(current);
372         current->flags.loaded = 0;
373         current->flags.preload_done = 0;
374      }
375    SLKU(current->lock_cancel);
376    SLKU(current->lock);
377 }
378 
379 static void
_evas_cache_image_preloaded_notify(Image_Entry * ie)380 _evas_cache_image_preloaded_notify(Image_Entry *ie)
381 {
382    Evas_Cache_Target *tmp;
383 
384    while ((tmp = ie->targets))
385      {
386         ie->targets = (Evas_Cache_Target *)
387           eina_inlist_remove(EINA_INLIST_GET(ie->targets),
388                              EINA_INLIST_GET(ie->targets));
389         if (ie->load_opts.skip_head && !tmp->delete_me && !tmp->preload_cancel)
390           _evas_image_preload_update((void*)tmp->target, ie->f);
391         if (!tmp->delete_me && tmp->preloaded_cb)
392           tmp->preloaded_cb(tmp->preloaded_data);
393         if (!tmp->preload_cancel)
394           evas_object_inform_call_image_preloaded((Eo*) tmp->target);
395         free(tmp);
396      }
397 }
398 
399 static void
_evas_cache_image_async_end(void * data)400 _evas_cache_image_async_end(void *data)
401 {
402    Image_Entry *ie = (Image_Entry *)data;
403 
404    if (!ie->cache) return;
405    evas_cache_image_ref(ie);
406    ie->cache->preload = eina_list_remove(ie->cache->preload, ie);
407    ie->cache->pending = eina_list_remove(ie->cache->pending, ie);
408    ie->preload = NULL;
409    ie->flags.preload_done = ie->flags.loaded;
410    ie->flags.updated_data = 1;
411    ie->flags.preload_pending = 0;
412    ie->flags.loaded = EINA_TRUE;
413 
414    _evas_cache_image_preloaded_notify(ie);
415    evas_cache_image_drop(ie);
416 }
417 
418 static void
_evas_cache_image_async_cancel(void * data)419 _evas_cache_image_async_cancel(void *data)
420 {
421    Evas_Cache_Image *cache = NULL;
422    Image_Entry *ie = (Image_Entry *)data;
423 
424    if (!ie->cache) return;
425    evas_cache_image_ref(ie);
426    ie->preload = NULL;
427    ie->cache->pending = eina_list_remove(ie->cache->pending, ie);
428 
429    ie->flags.preload_pending = 0;
430 
431    if ((ie->flags.delete_me) || (ie->flags.dirty))
432      {
433         SLKL(engine_lock);
434         ie->flags.delete_me = 0;
435         SLKU(engine_lock);
436         evas_cache_image_drop(ie);
437         return;
438      }
439    if (ie->references == 0)
440      {
441         SLKL(engine_lock);
442         _evas_cache_image_lru_add(ie);
443         SLKU(engine_lock);
444         cache = ie->cache;
445      }
446    if (ie->flags.loaded) _evas_cache_image_async_end(ie);
447    //On Cancelling, they need to draw image directly.
448    else
449      {
450         while (ie->targets)
451           {
452              Evas_Cache_Target *tg = ie->targets;
453              ie->targets = (Evas_Cache_Target *)
454                 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
455                                    EINA_INLIST_GET(tg));
456              //FIXME: What/When they properly get a notification? Call in advance for compatibility.
457              evas_object_inform_call_image_preloaded((Eo*) tg->target);
458              free(tg);
459           }
460      }
461 
462    evas_cache_image_drop(ie);
463    if (cache) evas_cache_image_flush(cache);
464 }
465 
466 // note - preload_add assumes a target is ONLY added ONCE to the image
467 // entry. make sure you only add once, or remove first, then add
468 static int
_evas_cache_image_entry_preload_add(Image_Entry * ie,const Eo * target,void (* preloaded_cb)(void *),void * preloaded_data)469 _evas_cache_image_entry_preload_add(Image_Entry *ie, const Eo *target, void (*preloaded_cb)(void *), void *preloaded_data)
470 {
471    Evas_Cache_Target *tg;
472 
473    if (!ie->cache) return 0;
474    evas_cache_image_ref(ie);
475    if (ie->flags.preload_done)
476      {
477         evas_cache_image_drop(ie);
478         return 0;
479      }
480 
481    tg = calloc(1, sizeof(Evas_Cache_Target));
482    if (!tg)
483      {
484         evas_cache_image_drop(ie);
485         return 0;
486      }
487    tg->target = target;
488    tg->preloaded_cb = preloaded_cb;
489    tg->preloaded_data = preloaded_data;
490 
491    ie->targets = (Evas_Cache_Target *)
492       eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
493 
494    if (!ie->preload)
495      {
496         ie->cache->preload = eina_list_append(ie->cache->preload, ie);
497         ie->flags.pending = 0;
498         ie->flags.preload_pending = 1;
499         ie->preload = evas_preload_thread_run(_evas_cache_image_async_heavy,
500                                               _evas_cache_image_async_end,
501                                               _evas_cache_image_async_cancel,
502                                               ie);
503      }
504    evas_cache_image_drop(ie);
505    return 1;
506 }
507 
508 /* force: remove preload forcely. If one object cancel preload and draw image direcltly,
509  * all other targets of that preload will be affected this as well. */
510 static void
_evas_cache_image_entry_preload_remove(Image_Entry * ie,const Eo * target,Eina_Bool force)511 _evas_cache_image_entry_preload_remove(Image_Entry *ie, const Eo *target, Eina_Bool force)
512 {
513    Evas_Cache_Target *tg;
514 
515    if (!ie->cache) return;
516 //   evas_cache_image_ref(ie);
517    if (target)
518      {
519         EINA_INLIST_FOREACH(ie->targets, tg)
520           {
521              if (tg->target == target)
522                {
523                   tg->preload_cancel = EINA_TRUE;
524                   break;
525                }
526           }
527      }
528    else
529      {
530         while (ie->targets)
531           {
532              tg = ie->targets;
533              ie->targets = (Evas_Cache_Target *)
534                 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
535                                    EINA_INLIST_GET(tg));
536              free(tg);
537           }
538      }
539 
540    if ((!ie->targets || force) && (ie->preload && !ie->flags.pending))
541      {
542         ie->cache->preload = eina_list_remove(ie->cache->preload, ie);
543         ie->cache->pending = eina_list_append(ie->cache->pending, ie);
544         ie->flags.pending = 1;
545         evas_preload_thread_cancel(ie->preload);
546      }
547 //   evas_cache_image_drop(ie);
548 }
549 
550 EAPI int
evas_cache_image_usage_get(Evas_Cache_Image * cache)551 evas_cache_image_usage_get(Evas_Cache_Image *cache)
552 {
553    if (!cache) return 0;
554    return cache->usage;
555 }
556 
557 EAPI int
evas_cache_image_get(Evas_Cache_Image * cache)558 evas_cache_image_get(Evas_Cache_Image *cache)
559 {
560    if (!cache) return 0;
561    return cache->limit;
562 }
563 
564 EAPI void
evas_cache_image_set(Evas_Cache_Image * cache,unsigned int limit)565 evas_cache_image_set(Evas_Cache_Image *cache, unsigned int limit)
566 {
567    if (!cache) return;
568    if (cache->limit == limit)
569      {
570         return;
571      }
572    cache->limit = limit;
573    evas_cache_image_flush(cache);
574 }
575 
576 EAPI Evas_Cache_Image *
evas_cache_image_init(const Evas_Cache_Image_Func * cb)577 evas_cache_image_init(const Evas_Cache_Image_Func *cb)
578 {
579    Evas_Cache_Image *cache;
580 
581    if (_evas_cache_mutex_init++ == 0)
582      {
583         SLKI(engine_lock);
584      }
585 
586    cache = calloc(1, sizeof(Evas_Cache_Image));
587    if (!cache) return NULL;
588    cache->func = *cb;
589    cache->inactiv = eina_hash_string_superfast_new(NULL);
590    cache->activ = eina_hash_string_superfast_new(NULL);
591    cache->mmap_activ = eina_hash_string_superfast_new(NULL);
592    cache->mmap_inactiv = eina_hash_string_superfast_new(NULL);
593    cache->references = 1;
594    return cache;
595 }
596 
597 static Eina_Bool
_evas_cache_image_free_cb(EINA_UNUSED const Eina_Hash * hash,EINA_UNUSED const void * key,void * data,void * fdata)598 _evas_cache_image_free_cb(EINA_UNUSED const Eina_Hash *hash, EINA_UNUSED const void *key, void *data, void *fdata)
599 {
600    Eina_List **delete_list = fdata;
601    *delete_list = eina_list_prepend(*delete_list, data);
602    return EINA_TRUE;
603 }
604 
605 EAPI void
evas_cache_image_shutdown(Evas_Cache_Image * cache)606 evas_cache_image_shutdown(Evas_Cache_Image *cache)
607 {
608    Eina_List *delete_list;
609    Image_Entry  *im;
610 
611    cache->references--;
612    if (cache->references != 0)
613      {
614         return;
615      }
616 
617    EINA_LIST_FREE(cache->preload, im)
618      {
619         /* By doing that we are protecting us from destroying image when the cache is no longer available. */
620         im->flags.delete_me = 1;
621         _evas_cache_image_entry_preload_remove(im, NULL, EINA_TRUE);
622      }
623    evas_async_events_process();
624 
625    SLKL(engine_lock);
626    EINA_INLIST_FREE(cache->lru, im)
627      _evas_cache_image_entry_delete(cache, im);
628    EINA_INLIST_FREE(cache->lru_nodata, im)
629      _evas_cache_image_entry_delete(cache, im);
630 
631    /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */
632    while (cache->dirty)
633      {
634         im = (Image_Entry *)cache->dirty;
635         _evas_cache_image_entry_delete(cache, im);
636      }
637    delete_list = NULL;
638 
639    eina_hash_foreach(cache->activ, _evas_cache_image_free_cb, &delete_list);
640    eina_hash_foreach(cache->mmap_activ, _evas_cache_image_free_cb, &delete_list);
641    while (delete_list)
642      {
643         _evas_cache_image_entry_delete(cache, eina_list_data_get(delete_list));
644         delete_list = eina_list_remove_list(delete_list, delete_list);
645      }
646    SLKU(engine_lock);
647 
648    /* Now wait for all pending image to die */
649    while (cache->pending)
650      {
651         im = eina_list_data_get(cache->pending);
652         evas_preload_thread_cancel(im->preload);
653 
654         evas_async_events_process();
655         if (!evas_preload_pthread_wait(im->preload, 1.0))
656           {
657              // We have waited long enough without reaction from that said
658              // thread, remove it from pending list and silently continue
659              // in the hope of an ok shutdown (but something is wrong).
660              cache->pending = eina_list_remove_list(cache->pending, cache->pending);
661              ERR("Could not stop decoding '%s' during shutdown.\n", im->file);
662           }
663      }
664 
665    eina_hash_free(cache->activ);
666    eina_hash_free(cache->inactiv);
667    eina_hash_free(cache->mmap_activ);
668    eina_hash_free(cache->mmap_inactiv);
669    free(cache);
670 
671    if (--_evas_cache_mutex_init == 0)
672      {
673         SLKD(engine_lock);
674      }
675 }
676 
677 static const Evas_Image_Load_Opts prevent = {
678    {
679         { 0, 0, 0, 0 },
680         {
681            0, 0, 0, 0,
682            0, 0,
683            0,
684            0
685         },
686       0.0,
687       0, 0,
688       0,
689       0,
690 
691       EINA_FALSE
692    },
693    EINA_FALSE
694 };
695 
696 static size_t
_evas_cache_image_loadopts_append(char * hkey,Evas_Image_Load_Opts ** plo)697 _evas_cache_image_loadopts_append(char *hkey, Evas_Image_Load_Opts **plo)
698 {
699    Evas_Image_Load_Opts *lo = *plo;
700    size_t offset = 0;
701 
702    if ((!lo) ||
703        (lo &&
704            (lo->emile.scale_down_by == 0) &&
705            (EINA_DBL_EQ(lo->emile.dpi, 0.0)) &&
706            ((lo->emile.w == 0) || (lo->emile.h == 0)) &&
707            ((lo->emile.region.w == 0) || (lo->emile.region.h == 0)) &&
708            (lo->emile.orientation == 0)
709        ))
710      {
711         *plo = (Evas_Image_Load_Opts*) &prevent;
712      }
713    else
714      {
715         memcpy(hkey, "//@/", 4);
716         offset += 4;
717         offset += eina_convert_xtoa(lo->emile.scale_down_by, hkey + offset);
718         hkey[offset] = '/';
719         offset += 1;
720         offset += eina_convert_dtoa(lo->emile.dpi, hkey + offset);
721         hkey[offset] = '/';
722         offset += 1;
723         offset += eina_convert_xtoa(lo->emile.w, hkey + offset);
724         hkey[offset] = 'x';
725         offset += 1;
726         offset += eina_convert_xtoa(lo->emile.h, hkey + offset);
727         hkey[offset] = '/';
728         offset += 1;
729         offset += eina_convert_xtoa(lo->emile.region.x, hkey + offset);
730         hkey[offset] = '+';
731         offset += 1;
732         offset += eina_convert_xtoa(lo->emile.region.y, hkey + offset);
733         hkey[offset] = '.';
734         offset += 1;
735         offset += eina_convert_xtoa(lo->emile.region.w, hkey + offset);
736         hkey[offset] = 'x';
737         offset += 1;
738         offset += eina_convert_xtoa(lo->emile.region.h, hkey + offset);
739 
740         if (lo->emile.orientation)
741           {
742              hkey[offset] = '/';
743              offset += 1;
744              hkey[offset] = 'o';
745              offset += 1;
746           }
747      }
748    hkey[offset] = '\0';
749 
750    return offset;
751 }
752 
753 EAPI Image_Entry *
evas_cache_image_mmap_request(Evas_Cache_Image * cache,Eina_File * f,const char * key,Evas_Image_Load_Opts * lo,int * error)754 evas_cache_image_mmap_request(Evas_Cache_Image *cache,
755                               Eina_File *f, const char *key,
756                               Evas_Image_Load_Opts *lo, int *error)
757 {
758    const char  *hexcode = "0123456789abcdef";
759    const char  *ckey = "(null)";
760    char        *hkey;
761    char        *pf;
762    Image_Entry *im;
763    size_t       size;
764    size_t       file_length;
765    size_t       key_length;
766    unsigned int i;
767 
768    // FIXME: In the long term we should certainly merge both mmap and filename path
769    //  by just using the mmap path. But for the time being, let's just have two path
770    //  as it is unlikely to really have an impact on real world application
771    if (!f)
772      {
773         *error = EVAS_LOAD_ERROR_GENERIC;
774         return NULL;
775      }
776 
777    /* generate hkey from file+key+load opts */
778    file_length = sizeof (Eina_File*) * 2;
779    key_length = key ? strlen(key) : 6;
780    size = file_length + key_length + 400; // enough padding for loadopts_append
781    hkey = alloca(sizeof (char) * size);
782    pf = (char*) &f;
783    for (size = 0, i = 0; i < sizeof (Eina_File*); i++)
784      {
785         hkey[size++] = hexcode[(pf[i] & 0xF0) >> 4];
786         hkey[size++] = hexcode[(pf[i] & 0x0F)];
787      }
788    memcpy(hkey + size, "//://", 5);
789    size += 5;
790    if (key) ckey = key;
791    memcpy(hkey + size, ckey, key_length);
792    size += key_length;
793    size += _evas_cache_image_loadopts_append(hkey + size, &lo);
794 
795 
796    /* find image by key in active mmap hash */
797    SLKL(engine_lock);
798    im = eina_hash_find(cache->mmap_activ, hkey);
799    if (im)
800      {
801         if (im->f != f)
802           {
803              /* as active cache find - if we match in lru and its invalid, dirty */
804              _evas_cache_image_dirty_add(im);
805              /* this image never used, so it have to be deleted */
806              _evas_cache_image_entry_delete(cache, im);
807              im = NULL;
808           }
809         else if (!im->load_failed) goto on_ok;
810         else if (im->load_failed)
811           {
812              _evas_cache_image_dirty_add(im);
813              im = NULL;
814           }
815      }
816 
817    /* find image by key in inactive/lru hash */
818    im = eina_hash_find(cache->mmap_inactiv, hkey);
819    if (im)
820      {
821         if (im->f != f)
822           {
823              /* as active cache find - if we match in lru and its invalid, dirty */
824              _evas_cache_image_dirty_add(im);
825              /* this image never used, so it have to be deleted */
826              _evas_cache_image_entry_delete(cache, im);
827              im = NULL;
828           }
829         else if (!im->load_failed)
830           {
831              _evas_cache_image_lru_del(im);
832              _evas_cache_image_activ_add(im);
833              goto on_ok;
834           }
835      }
836 
837    im = _evas_cache_image_entry_new(cache, hkey, NULL, f, NULL, key, lo, error);
838    if (!im)
839      {
840         SLKU(engine_lock);
841         return NULL;
842      }
843 
844  on_ok:
845    *error = EVAS_LOAD_ERROR_NONE;
846    im->references++;
847    SLKU(engine_lock);
848    return im;
849 }
850 
851 
852 EAPI Image_Entry *
evas_cache_image_request(Evas_Cache_Image * cache,const char * file,const char * key,Evas_Image_Load_Opts * lo,int * error)853 evas_cache_image_request(Evas_Cache_Image *cache, const char *file,
854                          const char *key, Evas_Image_Load_Opts *lo, int *error)
855 {
856    const char           *ckey = "(null)";
857    char                 *hkey;
858    Image_Entry          *im;
859    size_t                size;
860    int                   stat_done = 0, stat_failed = 0;
861    size_t                file_length;
862    size_t                key_length;
863    struct stat           st;
864    Image_Timestamp       tstamp;
865    Evas_Image_Load_Opts  tlo;
866    Eina_Bool             skip = lo->skip_head;
867 
868    if (!file)
869      {
870         *error = EVAS_LOAD_ERROR_GENERIC;
871         return NULL;
872      }
873 
874    /* generate hkey from file+key+load opts */
875    file_length = strlen(file);
876    key_length = key ? strlen(key) : 6;
877    size = file_length + key_length + 132;
878    hkey = alloca(sizeof (char) * size);
879    memcpy(hkey, file, file_length);
880    size = file_length;
881    memcpy(hkey + size, "//://", 5);
882    size += 5;
883    if (key) ckey = key;
884    memcpy(hkey + size, ckey, key_length);
885    size += key_length;
886    size += _evas_cache_image_loadopts_append(hkey + size, &lo);
887    tlo = *lo;
888    tlo.skip_head = skip;
889 
890    /* find image by key in active hash */
891    SLKL(engine_lock);
892    im = eina_hash_find(cache->activ, hkey);
893    if ((im) && (!im->load_failed))
894      {
895         int ok = 1;
896 
897         stat_done = 1;
898         if (stat(file, &st) < 0)
899           {
900              stat_failed = 1;
901              ok = 0;
902           }
903         else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
904 
905         if (ok) goto on_ok;
906         /* image we found doesn't match what's on disk (stat info wise)
907          * so dirty the active cache entry so we never find it again. this
908          * also implicitly guarantees that we only have 1 active copy
909          * of an image at a given key. we wither find it and keep re-reffing
910          * it or we dirty it and get it out */
911         _evas_cache_image_dirty_add(im);
912         im = NULL;
913      }
914    else if ((im) && (im->load_failed))
915      {
916         _evas_cache_image_dirty_add(im);
917         im = NULL;
918      }
919 
920    /* find image by key in inactive/lru hash */
921    im = eina_hash_find(cache->inactiv, hkey);
922    if ((im) && (!im->load_failed))
923      {
924         int ok = 1;
925 
926         if (!stat_done)
927           {
928              stat_done = 1;
929              if (stat(file, &st) < 0)
930                {
931                   stat_failed = 1;
932                        ok = 0;
933                }
934              else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
935           }
936         else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
937 
938         if (ok)
939           {
940              /* remove from lru and make it active again */
941              _evas_cache_image_lru_del(im);
942              _evas_cache_image_activ_add(im);
943              goto on_ok;
944           }
945         /* as active cache find - if we match in lru and its invalid, dirty */
946         _evas_cache_image_dirty_add(im);
947         /* this image never used, so it have to be deleted */
948         _evas_cache_image_entry_delete(cache, im);
949         im = NULL;
950      }
951    else if ((im) && (im->load_failed))
952      {
953         /* as active cache find - if we match in lru and its invalid, dirty */
954         _evas_cache_image_dirty_add(im);
955         /* this image never used, so it have to be deleted */
956         _evas_cache_image_entry_delete(cache, im);
957         im = NULL;
958      }
959    if (stat_failed) goto on_stat_error;
960 
961    if (!stat_done)
962      {
963         if (stat(file, &st) < 0) goto on_stat_error;
964      }
965    _timestamp_build(&tstamp, &st);
966    im = _evas_cache_image_entry_new(cache, hkey, &tstamp, NULL,
967                                     file, key, &tlo, error);
968    if (!im) goto on_stat_error;
969    if (cache->func.debug) cache->func.debug("request", im);
970 
971 on_ok:
972    *error = EVAS_LOAD_ERROR_NONE;
973 ////   SLKL(im->lock);
974    im->references++;
975 ////   SLKU(im->lock);
976    SLKU(engine_lock);
977    return im;
978 
979 on_stat_error:
980 #ifndef _WIN32
981    if ((errno == ENOENT) || (errno == ENOTDIR) ||
982        (errno == ENAMETOOLONG) || (errno == ELOOP))
983 #else
984      if (errno == ENOENT)
985 #endif
986        *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
987 #ifndef _WIN32
988      else if ((errno == ENOMEM) || (errno == EOVERFLOW))
989 #else
990      else if (errno == ENOMEM)
991 #endif
992        *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
993      else if (errno == EACCES)
994        *error = EVAS_LOAD_ERROR_PERMISSION_DENIED;
995      else
996        *error = EVAS_LOAD_ERROR_GENERIC;
997 
998    SLKU(engine_lock);
999    return NULL;
1000 }
1001 
1002 EAPI void
evas_cache_image_ref(Image_Entry * im)1003 evas_cache_image_ref(Image_Entry *im)
1004 {
1005    SLKL(engine_lock);
1006    im->references++;
1007    SLKU(engine_lock);
1008 }
1009 
1010 EAPI void
evas_cache_image_drop(Image_Entry * im)1011 evas_cache_image_drop(Image_Entry *im)
1012 {
1013    Evas_Cache_Image *cache;
1014    int references;
1015 
1016    if (!im->cache) return;
1017    SLKL(engine_lock);
1018    im->references--;
1019    if (im->references < 0) im->references = 0;
1020    references = im->references;
1021    SLKU(engine_lock);
1022 
1023    cache = im->cache;
1024 
1025    if (references == 0)
1026      {
1027         if (im->preload)
1028           {
1029              SLKL(engine_lock);
1030              _evas_cache_image_entry_preload_remove(im, NULL, EINA_TRUE);
1031              SLKU(engine_lock);
1032              return;
1033           }
1034         if ((im->flags.dirty) || (im->load_failed))
1035           {
1036              SLKL(engine_lock);
1037              _evas_cache_image_entry_delete(cache, im);
1038              SLKU(engine_lock);
1039              return;
1040           }
1041         if (cache)
1042           {
1043              SLKL(engine_lock);
1044              _evas_cache_image_lru_add(im);
1045              SLKU(engine_lock);
1046              evas_cache_image_flush(cache);
1047           }
1048      }
1049 }
1050 
1051 EAPI void
evas_cache_image_data_not_needed(Image_Entry * im)1052 evas_cache_image_data_not_needed(Image_Entry *im)
1053 {
1054    int references;
1055 
1056    references = im->references;
1057    if (references > 1) return;
1058    if ((im->flags.dirty) || (!im->flags.need_data)) return;
1059    SLKL(engine_lock);
1060    _evas_cache_image_lru_nodata_add(im);
1061    SLKU(engine_lock);
1062 }
1063 
1064 EAPI Image_Entry *
evas_cache_image_dirty(Image_Entry * im,unsigned int x,unsigned int y,unsigned int w,unsigned int h)1065 evas_cache_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
1066 {
1067    Image_Entry *im_dirty = im;
1068    Evas_Cache_Image *cache;
1069 
1070    if (!im->cache) return NULL;
1071    cache = im->cache;
1072    if (!(im->flags.dirty))
1073      {
1074         if (im->references == 1) im_dirty = im;
1075         else
1076           {
1077              im_dirty =
1078                 evas_cache_image_copied_data(cache, im->w, im->h,
1079                                              evas_cache_image_pixels(im),
1080                                              im->flags.alpha, im->space);
1081              if (!im_dirty) goto on_error;
1082              if (cache->func.debug) cache->func.debug("dirty-src", im);
1083              cache->func.dirty(im_dirty, im);
1084              if (cache->func.debug) cache->func.debug("dirty-out", im_dirty);
1085              im_dirty->references = 1;
1086              evas_cache_image_drop(im);
1087           }
1088         SLKL(engine_lock);
1089         _evas_cache_image_dirty_add(im_dirty);
1090         SLKU(engine_lock);
1091      }
1092 
1093    if (cache->func.debug) cache->func.debug("dirty-region", im_dirty);
1094    if (cache->func.dirty_region)
1095      cache->func.dirty_region(im_dirty, x, y, w, h);
1096    return im_dirty;
1097 
1098 on_error:
1099    evas_cache_image_drop(im);
1100    return NULL;
1101 }
1102 
1103 EAPI Image_Entry *
evas_cache_image_alone(Image_Entry * im)1104 evas_cache_image_alone(Image_Entry *im)
1105 {
1106    Evas_Cache_Image *cache;
1107    Image_Entry *im_dirty = im;
1108    int references;
1109 
1110    if (!im->cache) return NULL;
1111    cache = im->cache;
1112    references = im->references;
1113 
1114    if (references <= 1)
1115      {
1116         SLKL(engine_lock);
1117         if (!im->flags.dirty) _evas_cache_image_dirty_add(im);
1118         SLKU(engine_lock);
1119      }
1120    else
1121      {
1122         im_dirty = evas_cache_image_copied_data(cache, im->w, im->h,
1123                                                 evas_cache_image_pixels(im),
1124                                                 im->flags.alpha,
1125                                                 im->space);
1126         if (!im_dirty) goto on_error;
1127         if (cache->func.debug) cache->func.debug("dirty-src", im);
1128         cache->func.dirty(im_dirty, im);
1129         if (cache->func.debug) cache->func.debug("dirty-out", im_dirty);
1130         im_dirty->references = 1;
1131         evas_cache_image_drop(im);
1132      }
1133    return im_dirty;
1134 
1135 on_error:
1136    evas_cache_image_drop(im);
1137    return NULL;
1138 }
1139 
1140 EAPI Image_Entry *
evas_cache_image_copied_data(Evas_Cache_Image * cache,unsigned int w,unsigned int h,DATA32 * image_data,int alpha,Evas_Colorspace cspace)1141 evas_cache_image_copied_data(Evas_Cache_Image *cache,
1142                              unsigned int w, unsigned int h,
1143                              DATA32 *image_data, int alpha,
1144                              Evas_Colorspace cspace)
1145 {
1146    int err;
1147    Image_Entry *im;
1148 
1149    if (!cache) return NULL;
1150    if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
1151        (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
1152        (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
1153      w &= ~0x1;
1154 
1155    SLKL(engine_lock);
1156    im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL, &err);
1157    SLKU(engine_lock);
1158    if (!im) return NULL;
1159    im->space = cspace;
1160    im->flags.alpha = alpha;
1161    _evas_cache_image_entry_surface_alloc(cache, im, w, h);
1162    if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
1163      {
1164         SLKL(engine_lock);
1165         _evas_cache_image_entry_delete(cache, im);
1166         SLKU(engine_lock);
1167         return NULL;
1168      }
1169    im->references = 1;
1170    im->flags.loaded = EINA_TRUE;
1171    if (cache->func.debug) cache->func.debug("copied-data", im);
1172    return im;
1173 }
1174 
1175 EAPI Image_Entry *
evas_cache_image_data(Evas_Cache_Image * cache,unsigned int w,unsigned int h,DATA32 * image_data,int alpha,Evas_Colorspace cspace)1176 evas_cache_image_data(Evas_Cache_Image *cache, unsigned int w, unsigned int h,
1177                       DATA32 *image_data, int alpha, Evas_Colorspace cspace)
1178 {
1179    int err;
1180    Image_Entry *im;
1181 
1182    if (!cache) return NULL;
1183    if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
1184        (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
1185        (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
1186      w &= ~0x1;
1187 
1188    SLKL(engine_lock);
1189    im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL, &err);
1190    SLKU(engine_lock);
1191    if (!im) return NULL;
1192    im->w = w;
1193    im->h = h;
1194    im->flags.alpha = alpha;
1195    if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
1196      {
1197         SLKL(engine_lock);
1198         _evas_cache_image_entry_delete(cache, im);
1199         SLKU(engine_lock);
1200         return NULL;
1201      }
1202    im->references = 1;
1203    im->flags.loaded = EINA_TRUE;
1204    if (cache->func.debug) cache->func.debug("data", im);
1205    return im;
1206 }
1207 
1208 EAPI void
evas_cache_image_surface_alloc(Image_Entry * im,unsigned int w,unsigned int h)1209 evas_cache_image_surface_alloc(Image_Entry *im, unsigned int w, unsigned int h)
1210 {
1211    Evas_Cache_Image *cache = im->cache;
1212 
1213    if (!im->cache) return;
1214    if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
1215        (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
1216        (im->space == EVAS_COLORSPACE_YCBCR422601_PL))
1217      w &= ~0x1;
1218 
1219    _evas_cache_image_entry_surface_alloc(cache, im, w, h);
1220    if (cache->func.debug) cache->func.debug("surface-alloc", im);
1221 }
1222 
1223 EAPI Image_Entry *
evas_cache_image_size_set(Image_Entry * im,unsigned int w,unsigned int h)1224 evas_cache_image_size_set(Image_Entry *im, unsigned int w, unsigned int h)
1225 {
1226    Evas_Cache_Image *cache;
1227    Image_Entry *im2 = NULL;
1228    int error;
1229 
1230    if (!im->cache) return im;
1231    evas_cache_image_ref(im);
1232    if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
1233        (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
1234        (im->space == EVAS_COLORSPACE_YCBCR422601_PL))
1235      w &= ~0x1;
1236    if ((im->w == w) && (im->h == h))
1237      {
1238         evas_cache_image_drop(im);
1239         return im;
1240      }
1241 
1242    cache = im->cache;
1243    SLKL(engine_lock);
1244    im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL, &error);
1245    SLKU(engine_lock);
1246    if (!im2) goto on_error;
1247 
1248    im2->flags.alpha = im->flags.alpha;
1249    im2->space = im->space;
1250    im2->load_opts = im->load_opts;
1251    _evas_cache_image_entry_surface_alloc(cache, im2, w, h);
1252    error = cache->func.size_set(im2, im, w, h);
1253    if (error != 0) goto on_error;
1254    im2->references = 1;
1255    im2->flags.loaded = EINA_TRUE;
1256    if (cache->func.debug) cache->func.debug("size_set", im2);
1257    /* this drop is for handling refereces in this function */
1258    evas_cache_image_drop(im);
1259    /* we don't need im at this point, drop it! */
1260    evas_cache_image_drop(im);
1261    return im2;
1262 
1263 on_error:
1264    SLKL(engine_lock);
1265    if (im2) _evas_cache_image_entry_delete(cache, im2);
1266    SLKU(engine_lock);
1267    /* this drop is for handling refereces in this function */
1268    evas_cache_image_drop(im);
1269    /* we don't need im at this point, drop it! */
1270    evas_cache_image_drop(im);
1271    return NULL;
1272 }
1273 
1274 EAPI int
evas_cache_image_load_data(Image_Entry * im)1275 evas_cache_image_load_data(Image_Entry *im)
1276 {
1277    Eina_Bool preload = EINA_FALSE;
1278    int error = EVAS_LOAD_ERROR_NONE;
1279 
1280    if (!im->cache) return error;
1281    evas_cache_image_ref(im);
1282    if ((im->flags.loaded) && (!im->animated.animated))
1283      {
1284         evas_cache_image_drop(im);
1285         return error;
1286      }
1287    evas_common_rgba_pending_unloads_remove(im);
1288    if (im->preload)
1289      {
1290         preload = EINA_TRUE;
1291         if (!im->flags.pending)
1292           {
1293              im->cache->preload = eina_list_remove(im->cache->preload, im);
1294              im->cache->pending = eina_list_append(im->cache->pending, im);
1295              im->flags.pending = 1;
1296              evas_preload_thread_cancel(im->preload);
1297           }
1298         evas_async_events_process();
1299         evas_preload_pthread_wait(im->preload, 0.01);
1300 
1301         while (im->flags.preload_pending)
1302           {
1303              evas_async_events_process();
1304              evas_preload_pthread_wait(im->preload, 0.1);
1305           }
1306      }
1307 
1308    if ((im->flags.loaded) && (!im->animated.animated))
1309      {
1310         evas_cache_image_drop(im);
1311         return error;
1312      }
1313 
1314    SLKL(im->lock);
1315    im->flags.in_progress = EINA_TRUE;
1316    error = im->cache->func.load(im);
1317    im->flags.in_progress = EINA_FALSE;
1318    SLKU(im->lock);
1319 
1320    im->flags.loaded = 1;
1321    if (im->cache->func.debug) im->cache->func.debug("load", im);
1322    if (error != EVAS_LOAD_ERROR_NONE)
1323      {
1324         _evas_cache_image_entry_surface_alloc(im->cache, im, im->w, im->h);
1325         im->flags.loaded = 0;
1326      }
1327    if (preload) _evas_cache_image_async_end(im);
1328    evas_cache_image_drop(im);
1329    return error;
1330 }
1331 
1332 EAPI void
evas_cache_image_unload_data(Image_Entry * im)1333 evas_cache_image_unload_data(Image_Entry *im)
1334 {
1335    if (!im->cache) return;
1336    evas_cache_image_ref(im);
1337    if (im->flags.in_progress)
1338      {
1339         evas_cache_image_drop(im);
1340         return;
1341      }
1342    evas_cache_image_preload_cancel(im, NULL, EINA_TRUE);
1343 
1344    if (SLKT(im->lock) == EINA_FALSE) /* can't get image lock - busy async load */
1345      {
1346         SLKL(im->lock_cancel);
1347         im->flags.unload_cancel = EINA_TRUE;
1348         SLKU(im->lock_cancel);
1349         evas_cache_image_drop(im);
1350         return;
1351      }
1352 
1353    SLKL(im->lock_cancel);
1354    if ((!im->flags.loaded) || (!im->file && !im->f) || (!im->info.module) ||
1355        (im->flags.dirty))
1356      {
1357         SLKU(im->lock_cancel);
1358         SLKU(im->lock);
1359         evas_cache_image_drop(im);
1360         return;
1361      }
1362    SLKU(im->lock_cancel);
1363    im->cache->func.destructor(im);
1364    SLKU(im->lock);
1365    evas_cache_image_drop(im);
1366    //FIXME: imagedataunload - inform owners
1367 }
1368 
1369 static Eina_Bool
_evas_cache_image_unload_cb(EINA_UNUSED const Eina_Hash * hash,EINA_UNUSED const void * key,void * data,EINA_UNUSED void * fdata)1370 _evas_cache_image_unload_cb(EINA_UNUSED const Eina_Hash *hash, EINA_UNUSED const void *key, void *data, EINA_UNUSED void *fdata)
1371 {
1372    evas_cache_image_unload_data(data);
1373    return EINA_TRUE;
1374 }
1375 
1376 EAPI void
evas_cache_image_unload_all(Evas_Cache_Image * cache)1377 evas_cache_image_unload_all(Evas_Cache_Image *cache)
1378 {
1379    Image_Entry *im;
1380 
1381    if (!cache) return;
1382 // _evas_cache_image_unload_cb -> evas_cache_image_unload_data -> evas_cache_image_ref
1383 //  deadlock
1384 //////   SLKL(engine_lock);
1385    EINA_INLIST_FOREACH(cache->lru, im) evas_cache_image_unload_data(im);
1386    EINA_INLIST_FOREACH(cache->lru_nodata, im) evas_cache_image_unload_data(im);
1387    eina_hash_foreach(cache->activ, _evas_cache_image_unload_cb, NULL);
1388    eina_hash_foreach(cache->inactiv, _evas_cache_image_unload_cb, NULL);
1389 //////   SLKU(engine_lock);
1390 }
1391 
1392 static int async_frozen = 0;
1393 
1394 EAPI int
evas_cache_async_frozen_get(void)1395 evas_cache_async_frozen_get(void)
1396 {
1397    return async_frozen;
1398 }
1399 
1400 EAPI void
evas_cache_async_freeze(void)1401 evas_cache_async_freeze(void)
1402 {
1403    async_frozen++;
1404 }
1405 
1406 EAPI void
evas_cache_async_thaw(void)1407 evas_cache_async_thaw(void)
1408 {
1409    async_frozen--;
1410 }
1411 
1412 EAPI Eina_Bool
evas_cache_image_is_loaded(Image_Entry * im)1413 evas_cache_image_is_loaded(Image_Entry *im)
1414 {
1415    if (im->flags.loaded) return EINA_TRUE;
1416    return EINA_FALSE;
1417 }
1418 
1419 EAPI void
evas_cache_image_preload_data(Image_Entry * im,const Eo * target,void (* preloaded_cb)(void *),void * preloaded_data)1420 evas_cache_image_preload_data(Image_Entry *im, const Eo *target, void (*preloaded_cb)(void *), void *preloaded_data)
1421 {
1422    RGBA_Image *img = (RGBA_Image *)im;
1423 
1424    if (!im->cache) return;
1425    evas_cache_image_ref(im);
1426    if (((int)im->w > 0) && ((int)im->h > 0) &&
1427        (((im->flags.loaded) && (img->image.data)) ||
1428         (im->flags.textured && !im->flags.updated_data)))
1429      {
1430         _evas_cache_image_preloaded_notify(im);
1431         evas_object_inform_call_image_preloaded((Evas_Object*)target);
1432         evas_cache_image_drop(im);
1433         return;
1434      }
1435    im->flags.loaded = 0;
1436    if (!_evas_cache_image_entry_preload_add(im, target, preloaded_cb, preloaded_data))
1437      evas_object_inform_call_image_preloaded((Evas_Object*) target);
1438    evas_cache_image_drop(im);
1439 }
1440 
1441 EAPI void
evas_cache_image_preload_cancel(Image_Entry * im,const Eo * target,Eina_Bool force)1442 evas_cache_image_preload_cancel(Image_Entry *im, const Eo *target, Eina_Bool force)
1443 {
1444    if (!target) return;
1445    evas_cache_image_ref(im);
1446    _evas_cache_image_entry_preload_remove(im, target, force);
1447    evas_cache_image_drop(im);
1448 }
1449 
1450 #ifdef CACHEDUMP
1451 static int total = 0;
1452 
1453 static void
_dump_img(Image_Entry * im,const char * type)1454 _dump_img(Image_Entry *im, const char *type)
1455 {
1456    if (!im->cache) return;
1457    total += im->cache->func.mem_size_get(im);
1458    printf("%s: %4i: %4ib, %4ix%4i alloc[%4ix%4i] [%s] [%s]\n",
1459           type,
1460           im->references,
1461           im->cache->func.mem_size_get(im),
1462           im->w, im->h, im->allocated.w, im->allocated.h,
1463           im->f ? eina_file_filename_get(im->f) : im->file, im->key);
1464 }
1465 
1466 static Eina_Bool
_dump_cache_active(EINA_UNUSED const Eina_Hash * hash,EINA_UNUSED const void * key,void * data,void * fdata EINA_UNUSED)1467 _dump_cache_active(EINA_UNUSED const Eina_Hash *hash, EINA_UNUSED const void *key, void *data, void *fdata EINA_UNUSED)
1468 {
1469    Image_Entry *im = data;
1470    _dump_img(im, "ACTIVE");
1471    return EINA_TRUE;
1472 }
1473 
1474 static void
_dump_cache(Evas_Cache_Image * cache)1475 _dump_cache(Evas_Cache_Image *cache)
1476 {
1477    Image_Entry *im;
1478 
1479    if (!cache) return;
1480    printf("--CACHE DUMP----------------------------------------------------\n");
1481    printf("cache: %ikb / %ikb\n",
1482           cache->usage / 1024,
1483           cache->limit / 1024);
1484    printf("................................................................\n");
1485    total = 0;
1486    SLKL(engine_lock);
1487    EINA_INLIST_FOREACH(cache->lru_nodata, im)
1488       _dump_img(im, "NODATA");
1489    EINA_INLIST_FOREACH(cache->lru, im)
1490       _dump_img(im, "DATA  ");
1491    printf("tot: %i\n"
1492           "usg: %i\n",
1493           total,
1494           cache->usage);
1495    eina_hash_foreach(cache->activ, _dump_cache_active, NULL);
1496    SLKU(engine_lock);
1497 }
1498 #endif
1499 
1500 EAPI int
evas_cache_image_flush(Evas_Cache_Image * cache)1501 evas_cache_image_flush(Evas_Cache_Image *cache)
1502 {
1503    if (!cache) return 0;
1504 #ifdef CACHEDUMP
1505    _dump_cache(cache);
1506 #endif
1507    if (cache->limit == (unsigned int)-1) return -1;
1508 
1509    SLKL(engine_lock);
1510    while ((cache->lru) && (cache->limit < (unsigned int)cache->usage))
1511      {
1512         Image_Entry *im;
1513 
1514         im = (Image_Entry *)cache->lru->last;
1515         if (!im) im = (Image_Entry *)cache->lru;
1516         _evas_cache_image_entry_delete(cache, im);
1517      }
1518 
1519    while ((cache->lru_nodata) && (cache->limit < (unsigned int)cache->usage))
1520      {
1521         Image_Entry *im;
1522 
1523         im = (Image_Entry *)cache->lru_nodata->last;
1524         if (!im) im = (Image_Entry *)cache->lru_nodata;
1525         _evas_cache_image_lru_nodata_del(im);
1526         cache->func.surface_delete(im);
1527         im->flags.loaded = 0;
1528      }
1529    SLKU(engine_lock);
1530 
1531    return cache->usage;
1532 }
1533 
1534 EAPI Image_Entry *
evas_cache_image_empty(Evas_Cache_Image * cache)1535 evas_cache_image_empty(Evas_Cache_Image *cache)
1536 {
1537    int err;
1538    Image_Entry *im;
1539 
1540    if (!cache) return NULL;
1541    SLKL(engine_lock);
1542    im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL, &err);
1543    SLKU(engine_lock);
1544    if (!im) return NULL;
1545    im->references = 1;
1546    return im;
1547 }
1548 
1549 EAPI void
evas_cache_image_colorspace(Image_Entry * im,Evas_Colorspace cspace)1550 evas_cache_image_colorspace(Image_Entry *im, Evas_Colorspace cspace)
1551 {
1552    if (!im->cache) return;
1553    evas_cache_image_ref(im);
1554    if (im->space == cspace) goto done;
1555    im->space = cspace;
1556    if (!im->cache) goto done;
1557    im->cache->func.color_space(im, cspace);
1558 done:
1559    evas_cache_image_drop(im);
1560 }
1561 
1562 EAPI void *
evas_cache_private_from_image_entry_get(Image_Entry * im)1563 evas_cache_private_from_image_entry_get(Image_Entry *im)
1564 {
1565    void *data;
1566    if (!im->cache) return NULL;
1567    evas_cache_image_ref(im);
1568    data = (void *)im->cache->data;
1569    evas_cache_image_drop(im);
1570    return data;
1571 }
1572 
1573 EAPI void *
evas_cache_private_get(Evas_Cache_Image * cache)1574 evas_cache_private_get(Evas_Cache_Image *cache)
1575 {
1576    if (!cache) return NULL;
1577    return cache->data;
1578 }
1579 
1580 EAPI void
evas_cache_private_set(Evas_Cache_Image * cache,const void * data)1581 evas_cache_private_set(Evas_Cache_Image *cache, const void *data)
1582 {
1583    if (!cache) return;
1584    cache->data = (void *)data;
1585 }
1586 
1587 EAPI DATA32 *
evas_cache_image_pixels(Image_Entry * im)1588 evas_cache_image_pixels(Image_Entry *im)
1589 {
1590    if (!im->cache) return NULL;
1591    return im->cache->func.surface_pixels(im);
1592 }
1593