move around - flatter.
[profile/ivi/evas.git] / src / lib / cache / evas_cache_image.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include <stdlib.h>
6 #include <assert.h>
7
8 #include "evas_common.h"
9 #include "evas_private.h"
10
11 #define FREESTRC(Var)              \
12   if (Var)                         \
13     {                              \
14        evas_stringshare_del(Var);  \
15        Var = NULL;                 \
16     }
17
18 static void _evas_cache_image_entry_delete(Evas_Cache_Image *cache, Image_Entry *ie);
19
20 static void
21 _evas_cache_image_make_dirty(Evas_Cache_Image *cache,
22                              Image_Entry *im)
23 {
24    im->flags.cached = 1;
25    im->flags.dirty = 1;
26    im->flags.activ = 0;
27    im->flags.lru_nodata = 0;
28    cache->dirty = evas_object_list_prepend(cache->dirty, im);
29
30    if (im->cache_key)
31      {
32         evas_stringshare_del(im->cache_key);
33         im->cache_key = NULL;
34      }
35 }
36
37 static void
38 _evas_cache_image_make_activ(Evas_Cache_Image *cache,
39                              Image_Entry *im,
40                              const char *key)
41 {
42    im->cache_key = key;
43    if (key != NULL)
44      {
45         im->flags.cached = 1;
46         im->flags.activ = 1;
47         im->flags.lru_nodata = 0;
48         im->flags.dirty = 0;
49         cache->activ = evas_hash_direct_add(cache->activ, key, im);
50      }
51    else
52      {
53         _evas_cache_image_make_dirty(cache, im);
54      }
55 }
56
57 static void
58 _evas_cache_image_make_inactiv(Evas_Cache_Image *cache,
59                                Image_Entry *im,
60                                const char *key)
61 {
62    if (im->cache_key)
63      {
64         im->flags.activ = 0;
65         im->flags.dirty = 0;
66         im->flags.cached = 1;
67         cache->inactiv = evas_hash_direct_add(cache->inactiv, key, im);
68         cache->lru = evas_object_list_prepend(cache->lru, im);
69         cache->usage += cache->func.mem_size_get(im);
70      }
71    else
72      {
73         _evas_cache_image_entry_delete(cache, im);
74      }
75  }
76
77 static void
78 _evas_cache_image_remove_lru_nodata(Evas_Cache_Image *cache,
79                                     Image_Entry *im)
80 {
81    if (im->flags.lru_nodata)
82      {
83         im->flags.lru_nodata = 0;
84         cache->lru_nodata = evas_object_list_remove(cache->lru_nodata, im);
85         cache->usage -= cache->func.mem_size_get(im);
86      }
87 }
88
89 static void
90 _evas_cache_image_activ_lru_nodata(Evas_Cache_Image *cache,
91                                    Image_Entry *im)
92 {
93    im->flags.need_data = 0;
94    im->flags.lru_nodata = 1;
95    cache->lru_nodata = evas_object_list_prepend(cache->lru_nodata, im);
96    cache->usage += cache->func.mem_size_get(im);
97 }
98
99 static void
100 _evas_cache_image_remove_activ(Evas_Cache_Image *cache,
101                                Image_Entry *ie)
102 {
103    if (ie->flags.cached)
104      {
105         if (ie->flags.activ)
106           {
107              cache->activ = evas_hash_del(cache->activ, ie->cache_key, ie);
108              _evas_cache_image_remove_lru_nodata(cache, ie);
109           }
110         else
111           {
112              if (ie->flags.dirty)
113                {
114                   cache->dirty = evas_object_list_remove(cache->dirty, ie);
115                }
116              else
117                {
118                   cache->inactiv = evas_hash_del(cache->inactiv, ie->cache_key, ie);
119                   cache->lru = evas_object_list_remove(cache->lru, ie);
120                   cache->usage -= cache->func.mem_size_get(ie);
121                }
122           }
123         ie->flags.cached = 0;
124         ie->flags.dirty = 0;
125         ie->flags.activ = 0;
126      }
127 }
128
129 static void
130 _evas_cache_image_entry_delete(Evas_Cache_Image *cache, Image_Entry *ie)
131 {
132    if (!ie) return ;
133
134    if (cache->func.debug)
135      cache->func.debug("deleting", ie);
136
137    cache->func.destructor(ie);
138
139    _evas_cache_image_remove_activ(cache, ie);
140
141    if (ie->cache_key)
142      {
143         evas_stringshare_del(ie->cache_key);
144         ie->cache_key = NULL;
145      }
146
147    FREESTRC(ie->file);
148    FREESTRC(ie->key);
149
150    cache->func.surface_delete(ie);
151    cache->func.dealloc(ie);
152 }
153
154 static Image_Entry *
155 _evas_cache_image_entry_new(Evas_Cache_Image *cache,
156                             const char *hkey,
157                             time_t timestamp,
158                             const char *file,
159                             const char *key,
160                             RGBA_Image_Loadopts *lo,
161                             int *error)
162 {
163    Image_Entry  *ie;
164    const char   *cache_key;
165
166    ie = cache->func.alloc();
167    if (!ie)
168      return NULL;
169
170    cache_key = hkey ? evas_stringshare_add(hkey) : NULL;
171
172    ie->flags.loaded = 0;
173    ie->flags.need_data = 1;
174
175    _evas_cache_image_make_activ(cache, ie, cache_key);
176
177    ie->space = EVAS_COLORSPACE_ARGB8888;
178    ie->w = -1;
179    ie->h = -1;
180    ie->allocated.w = 0;
181    ie->allocated.h = 0;
182
183    ie->references = 0;
184    ie->cache = cache;
185
186    ie->file = file ? evas_stringshare_add(file) : NULL;
187    ie->key = key ? evas_stringshare_add(key) : NULL;
188
189    ie->timestamp = timestamp;
190    ie->laststat = time(NULL);
191
192    ie->load_opts.scale_down_by = 0;
193    ie->load_opts.dpi = 0;
194    ie->load_opts.w = 0;
195    ie->load_opts.h = 0;
196    ie->scale = 1;
197
198    if (lo)
199      ie->load_opts = *lo;
200
201    if (file)
202      {
203         *error = cache->func.constructor(ie);
204         if (*error != 0)
205           {
206              _evas_cache_image_entry_delete(cache, ie);
207              return NULL;
208           }
209      }
210    if (cache->func.debug)
211      cache->func.debug("build", ie);
212
213    return ie;
214 }
215
216 static void
217 _evas_cache_image_entry_surface_alloc(Evas_Cache_Image *cache,
218                                       Image_Entry *ie,
219                                       int w,
220                                       int h)
221 {
222    int  wmin;
223    int  hmin;
224
225    wmin = w > 0 ? w : 1;
226    hmin = h > 0 ? h : 1;
227    if (ie->allocated.w == wmin && ie->allocated.h == hmin)
228      return ;
229
230    if (cache->func.surface_alloc(ie, wmin, hmin))
231      {
232         wmin = 0;
233         hmin = 0;
234      }
235    ie->w = wmin;
236    ie->h = hmin;
237    ie->allocated.w = wmin;
238    ie->allocated.h = hmin;
239 }
240
241 EAPI int
242 evas_cache_image_usage_get(Evas_Cache_Image *cache)
243 {
244    assert(cache != NULL);
245
246    return cache->usage;
247 }
248
249 EAPI int
250 evas_cache_image_get(Evas_Cache_Image *cache)
251 {
252    assert(cache != NULL);
253
254    return cache->limit;
255 }
256
257 EAPI void
258 evas_cache_image_set(Evas_Cache_Image *cache, int limit)
259 {
260    assert(cache != NULL);
261    if (cache->limit == limit) return;
262    cache->limit = limit;
263    evas_cache_image_flush(cache);
264 }
265
266 EAPI Evas_Cache_Image *
267 evas_cache_image_init(const Evas_Cache_Image_Func *cb)
268 {
269    Evas_Cache_Image    *new;
270
271    new = malloc(sizeof (Evas_Cache_Image));
272    if (!new)
273      return NULL;
274
275    new->func = *cb;
276
277    new->limit = 0;
278    new->usage = 0;
279
280    new->dirty = NULL;
281    new->lru = NULL;
282    new->lru_nodata = NULL;
283    new->inactiv = NULL;
284    new->activ = NULL;
285
286    new->references = 1;
287
288    return new;
289 }
290
291 static Evas_Bool
292 _evas_cache_image_free_cb(const Evas_Hash *hash, const char *key, void *data, void *fdata)
293 {
294    Evas_Cache_Image    *cache = fdata;
295    Image_Entry         *im = data;
296
297    _evas_cache_image_entry_delete(cache, im);
298
299    return 1;
300 }
301
302 EAPI void
303 evas_cache_image_shutdown(Evas_Cache_Image *cache)
304 {
305    Image_Entry  *im;
306
307    assert(cache != NULL);
308    cache->references--;
309
310    if (cache->references > 0)
311      return ;
312
313    while (cache->lru)
314      {
315         im = (Image_Entry *) cache->lru;
316         _evas_cache_image_entry_delete(cache, im);
317      }
318
319    while (cache->lru_nodata)
320      {
321         im = (Image_Entry *) cache->lru_nodata;
322         _evas_cache_image_entry_delete(cache, im);
323      }
324
325    /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */
326    while (cache->dirty)
327      {
328         im = (Image_Entry *) cache->dirty;
329         _evas_cache_image_entry_delete(cache, im);
330      }
331
332    evas_hash_foreach(cache->activ, _evas_cache_image_free_cb, cache);
333    evas_hash_free(cache->activ);
334    evas_hash_free(cache->inactiv);
335
336    free(cache);
337 }
338
339 #define STAT_GAP 2
340
341 EAPI Image_Entry *
342 evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char *key, RGBA_Image_Loadopts *lo, int *error)
343 {
344    const char           *format;
345    char                 *hkey;
346    Image_Entry          *im;
347    Evas_Image_Load_Opts  prevent;
348    int                   size;
349    int                   stat_done = 0;
350    struct stat           st;
351
352    assert(cache != NULL);
353
354    if (!file && !key) return NULL;
355    if (!file) return NULL;
356    if ((!lo) ||
357        (lo &&
358         (lo->scale_down_by == 0) &&
359         (lo->dpi = 0.0) &&
360         ((lo->w == 0) || (lo->h == 0))))
361      {
362         lo = &prevent;
363         if (key)
364           format = "%s//://%s";
365         else
366           format = "%s//://%p";
367      }
368    else
369      {
370         if (key)
371           format = "%s//://%s//@/%i/%1.5f/%ix%i";
372         else
373           format = "%s//://%p//@/%i/%1.5f/%ix%i";
374      }
375    size = strlen(file) + (key ? strlen(key) : 6) + 64;
376    hkey = alloca(sizeof (char) * size);
377    snprintf(hkey, size, format, file, key, lo->scale_down_by, lo->dpi, lo->w, lo->h);
378
379    im = evas_hash_find(cache->activ, hkey);
380    if (im)
381      {
382         time_t  t;
383         int     ok;
384
385         ok = 1;
386         t = time(NULL);
387
388         if ((t - im->laststat) > STAT_GAP)
389           {
390              stat_done = 1;
391              if (stat(file, &st) < 0) goto on_error;
392
393              im->laststat = t;
394              if (st.st_mtime != im->timestamp) ok = 0;
395           }
396         if (ok) goto on_ok;
397
398         _evas_cache_image_remove_activ(cache, im);
399         _evas_cache_image_make_dirty(cache, im);
400      }
401
402    im = evas_hash_find(cache->inactiv, hkey);
403    if (im)
404      {
405         int     ok;
406
407         ok = 1;
408         if (!stat_done)
409           {
410              time_t  t;
411
412              t = time(NULL);
413              if ((t - im->laststat) > STAT_GAP)
414                {
415                   stat_done = 1;
416                   if (stat(file, &st) < 0) goto on_error;
417
418                   im->laststat = t;
419                   if (st.st_mtime != im->timestamp) ok = 0;
420                }
421           }
422         else
423           if (st.st_mtime != im->timestamp) ok = 0;
424
425         if (ok)
426           {
427              _evas_cache_image_remove_activ(cache, im);
428              _evas_cache_image_make_activ(cache, im, im->cache_key);
429              goto on_ok;
430           }
431
432         _evas_cache_image_entry_delete(cache, im);
433      }
434
435    if (!stat_done)
436      {
437         if (stat(file, &st) < 0) return NULL;
438      }
439
440    im = _evas_cache_image_entry_new(cache, hkey, st.st_mtime, file, key, lo, error);
441    if (!im)
442      return NULL;
443
444    if (cache->func.debug)
445      cache->func.debug("request", im);
446
447  on_ok:
448    *error = 0;
449    im->references++;
450    if (im->references > 1 && im->flags.lru_nodata)
451      _evas_cache_image_remove_lru_nodata(cache, im);
452
453    return im;
454
455  on_error:
456    _evas_cache_image_entry_delete(cache, im);
457    return NULL;
458 }
459
460 EAPI void
461 evas_cache_image_drop(Image_Entry *im)
462 {
463    Evas_Cache_Image    *cache;
464
465    assert(im);
466    assert(im->cache);
467
468    im->references--;
469    cache = im->cache;
470
471    if (im->references == 0)
472      {
473         if (im->flags.dirty)
474           {
475              _evas_cache_image_entry_delete(cache, im);
476              return ;
477           }
478
479         _evas_cache_image_remove_activ(cache, im);
480         _evas_cache_image_make_inactiv(cache, im, im->cache_key);
481         evas_cache_image_flush(cache);
482      }
483 }
484
485 EAPI void
486 evas_cache_image_data_not_needed(Image_Entry *im)
487 {
488    Evas_Cache_Image    *cache;
489
490    assert(im);
491    assert(im->cache);
492
493    cache = im->cache;
494
495    if (im->references > 1) return ;
496    if (im->flags.dirty || !im->flags.need_data) return ;
497
498    _evas_cache_image_activ_lru_nodata(cache, im);
499 }
500
501 EAPI Image_Entry *
502 evas_cache_image_dirty(Image_Entry *im, int x, int y, int w, int h)
503 {
504    Image_Entry          *im_dirty = im;
505    Evas_Cache_Image     *cache;
506
507    assert(im);
508    assert(im->cache);
509
510    cache = im->cache;
511    if (!(im->flags.dirty))
512      {
513         if (im->references == 1) im_dirty = im;
514         else
515           {
516              int        error;
517
518              im_dirty = _evas_cache_image_entry_new(cache, NULL, im->timestamp, im->file, im->key, &im->load_opts, &error);
519              if (!im_dirty) goto on_error;
520
521              if (cache->func.debug)
522                cache->func.debug("dirty-src", im);
523              error = cache->func.dirty(im_dirty, im);
524              if (cache->func.debug)
525                cache->func.debug("dirty-out", im_dirty);
526
527              if (error != 0) goto on_error;
528
529              im_dirty->references = 1;
530
531              evas_cache_image_drop(im);
532           }
533
534         _evas_cache_image_remove_activ(cache, im_dirty);
535         _evas_cache_image_make_dirty(cache, im_dirty);
536      }
537
538    if (cache->func.debug)
539      cache->func.debug("dirty-region", im_dirty);
540    if (cache->func.dirty_region)
541      cache->func.dirty_region(im_dirty, x, y, w, h);
542
543    return im_dirty;
544
545  on_error:
546    if (im_dirty) _evas_cache_image_entry_delete(cache, im_dirty);
547    evas_cache_image_drop(im);
548    return NULL;
549 }
550
551 EAPI Image_Entry *
552 evas_cache_image_alone(Image_Entry *im)
553 {
554    Evas_Cache_Image     *cache;
555    Image_Entry          *im_dirty = im;
556
557    assert(im);
558    assert(im->cache);
559
560    cache = im->cache;
561    if (im->references == 1)
562      {
563         if (!(im->flags.dirty))
564           {
565              _evas_cache_image_remove_activ(cache, im);
566              _evas_cache_image_make_dirty(cache, im);
567           }
568      }
569    else
570      {
571         int     error;
572
573         im_dirty = _evas_cache_image_entry_new(cache, NULL, im->timestamp, im->file, im->key, &im->load_opts, &error);
574         if (!im_dirty) goto on_error;
575
576         if (cache->func.debug)
577           cache->func.debug("dirty-src", im);
578         error = cache->func.dirty(im_dirty, im);
579         if (cache->func.debug)
580           cache->func.debug("dirty-out", im_dirty);
581
582         if (error != 0) goto on_error;
583
584         im_dirty->references = 1;
585
586         evas_cache_image_drop(im);
587      }
588
589    return im_dirty;
590    
591    on_error:
592    if (im_dirty) _evas_cache_image_entry_delete(cache, im_dirty);
593    evas_cache_image_drop(im);
594    return NULL;
595 }
596
597 EAPI Image_Entry *
598 evas_cache_image_copied_data(Evas_Cache_Image *cache, int w, int h, DATA32 *image_data, int alpha, int cspace)
599 {
600    Image_Entry  *im;
601
602    assert(cache);
603
604    if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
605        (cspace == EVAS_COLORSPACE_YCBCR422P709_PL))
606      w &= ~0x1;
607
608    im = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, NULL);
609    if (!im) return NULL;
610
611    im->space = cspace;
612    im->flags.alpha = alpha;
613
614    _evas_cache_image_entry_surface_alloc(cache, im, w, h);
615
616    if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
617      {
618         _evas_cache_image_entry_delete(cache, im);
619         return NULL;
620      }
621    im->references = 1;
622
623    if (cache->func.debug)
624      cache->func.debug("copied-data", im);
625    return im;
626 }
627
628 EAPI Image_Entry *
629 evas_cache_image_data(Evas_Cache_Image *cache, int w, int h, DATA32 *image_data, int alpha, int cspace)
630 {
631    Image_Entry  *im;
632
633    assert(cache);
634
635    if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
636        (cspace == EVAS_COLORSPACE_YCBCR422P709_PL))
637      w &= ~0x1;
638
639    im = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, NULL);
640    im->w = w;
641    im->h = h;
642    im->flags.alpha = alpha;
643
644    if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
645      {
646         _evas_cache_image_entry_delete(cache, im);
647         return NULL;
648      }
649    im->references = 1;
650
651    if (cache->func.debug)
652      cache->func.debug("data", im);
653    return im;
654 }
655
656 EAPI void
657 evas_cache_image_surface_alloc(Image_Entry *im, int w, int h)
658 {
659    Evas_Cache_Image     *cache;
660
661    assert(im);
662    assert(im->cache);
663
664    cache = im->cache;
665
666    if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
667        (im->space == EVAS_COLORSPACE_YCBCR422P709_PL))
668      w &= ~0x1;
669
670    _evas_cache_image_entry_surface_alloc(cache, im, w, h);
671
672    if (cache->func.debug)
673      cache->func.debug("surface-alloc", im);
674 }
675
676 EAPI Image_Entry *
677 evas_cache_image_size_set(Image_Entry *im, int w, int h)
678 {
679    Evas_Cache_Image    *cache;
680    Image_Entry         *new;
681    int                  error;
682
683    assert(im);
684    assert(im->cache);
685    assert(im->references > 0);
686
687    if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
688        (im->space == EVAS_COLORSPACE_YCBCR422P709_PL))
689      w &= ~0x1;
690
691    if ((im->w == w) && (im->h == h))
692      return im;
693
694    cache = im->cache;
695
696    new = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, &error);
697    if (!new) goto on_error;
698
699    new->flags.alpha = im->flags.alpha;
700    new->space = im->space;
701    new->load_opts = im->load_opts;
702
703    _evas_cache_image_entry_surface_alloc(cache, new, w, h);
704
705    error = cache->func.size_set(new, im, w, h);
706    if (error != 0) goto on_error;
707
708    new->references = 1;
709
710    evas_cache_image_drop(im);
711
712    if (cache->func.debug)
713      cache->func.debug("size_set", new);
714
715    return new;
716
717  on_error:
718    if (new) _evas_cache_image_entry_delete(cache, new);
719    evas_cache_image_drop(im);
720    return NULL;
721 }
722
723 EAPI void
724 evas_cache_image_load_data(Image_Entry *im)
725 {
726    Evas_Cache_Image    *cache;
727    int                  error;
728
729    assert(im);
730    assert(im->cache);
731
732    if (im->flags.loaded) return ;
733
734    cache = im->cache;
735
736    error = cache->func.load(im);
737
738    if (cache->func.debug)
739      cache->func.debug("load", im);
740
741    if (error)
742      {
743         _evas_cache_image_entry_surface_alloc(cache, im, im->w, im->h);
744         im->flags.loaded = 0;
745
746         return ;
747      }
748
749    im->flags.loaded = 1;
750 }
751
752 EAPI int
753 evas_cache_image_flush(Evas_Cache_Image *cache)
754 {
755    assert(cache);
756
757 //   printf("cache->limit = %i (used = %i)\n", cache->limit, cache->usage);
758    if (cache->limit == -1)
759      return -1;
760
761    while ((cache->lru) && (cache->limit < cache->usage))
762      {
763         Image_Entry     *im;
764
765         im = (Image_Entry *) cache->lru->last;
766         _evas_cache_image_entry_delete(cache, im);
767      }
768
769    while ((cache->lru_nodata) && (cache->limit < cache->usage))
770      {
771         Image_Entry     *im;
772
773         im = (Image_Entry *) cache->lru_nodata->last;
774         _evas_cache_image_remove_lru_nodata(cache, im);
775
776         cache->func.surface_delete(im);
777
778         im->flags.loaded = 0;
779      }
780
781    return cache->usage;
782 }
783
784 EAPI Image_Entry *
785 evas_cache_image_empty(Evas_Cache_Image *cache)
786 {
787    Image_Entry  *new;
788
789    new = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, NULL);
790    if (!new) return NULL;
791
792    new->references = 1;
793
794    return new;
795 }
796
797 EAPI void
798 evas_cache_image_colorspace(Image_Entry *im, int cspace)
799 {
800    Evas_Cache_Image    *cache;
801
802    assert(im);
803    assert(im->cache);
804
805    cache = im->cache;
806
807    if (im->space == cspace) return ;
808
809    im->space = cspace;
810    cache->func.color_space(im, cspace);
811 }
812
813 EAPI void *
814 evas_cache_private_from_image_entry_get(Image_Entry *im)
815 {
816    Evas_Cache_Image     *cache;
817
818    assert(im);
819    assert(im->cache);
820
821    cache = im->cache;
822
823    return (void*) cache->data;
824 }
825
826 EAPI void *
827 evas_cache_private_get(Evas_Cache_Image *cache)
828 {
829    assert(cache);
830
831    return cache->data;
832 }
833
834 EAPI void
835 evas_cache_private_set(Evas_Cache_Image *cache, const void *data)
836 {
837    assert(cache);
838
839    cache->data = data;
840 }
841
842 EAPI DATA32 *
843 evas_cache_image_pixels(Image_Entry *im)
844 {
845    Evas_Cache_Image    *cache;
846
847    assert(im);
848    assert(im->cache);
849
850    cache = im->cache;
851
852    return cache->func.surface_pixels(im);
853 }