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