2012-05-03 14:01:31 -07:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_EVIL
|
|
|
|
# include <Evil.h>
|
|
|
|
#endif
|
|
|
|
|
2013-06-20 03:53:29 -07:00
|
|
|
#include "evas_common_private.h"
|
2012-05-03 14:01:31 -07:00
|
|
|
#include "evas_private.h"
|
|
|
|
#include "evas_cache2.h"
|
|
|
|
#include "evas_cs2.h"
|
|
|
|
#include "evas_cs2_private.h"
|
|
|
|
|
|
|
|
#define FREESTRC(Var) \
|
|
|
|
if (Var) \
|
|
|
|
{ \
|
|
|
|
eina_stringshare_del(Var); \
|
|
|
|
Var = NULL; \
|
|
|
|
}
|
|
|
|
|
2012-11-27 10:23:25 -08:00
|
|
|
/* Size of characters used to determine a string that'll be used for load
|
|
|
|
* options in hash keys.
|
|
|
|
*/
|
|
|
|
#define HKEY_LOAD_OPTS_STR_LEN 215
|
|
|
|
|
2013-06-26 00:31:38 -07:00
|
|
|
// Default LRU size. If 0, all scaled images will be dropped instantly.
|
|
|
|
#define DEFAULT_CACHE_LRU_SIZE (4*1024*1024)
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
static void _evas_cache2_image_dirty_add(Image_Entry *im);
|
|
|
|
static void _evas_cache2_image_dirty_del(Image_Entry *im);
|
|
|
|
static void _evas_cache2_image_activ_add(Image_Entry *im);
|
|
|
|
static void _evas_cache2_image_activ_del(Image_Entry *im);
|
|
|
|
static void _evas_cache2_image_lru_add(Image_Entry *im);
|
|
|
|
static void _evas_cache2_image_lru_del(Image_Entry *im);
|
2012-05-03 14:01:31 -07:00
|
|
|
static void _evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target);
|
2013-08-26 03:59:24 -07:00
|
|
|
// static void _evas_cache2_image_lru_nodata_add(Image_Entry *im);
|
|
|
|
// static void _evas_cache2_image_lru_nodata_del(Image_Entry *im);
|
2012-05-03 14:01:31 -07:00
|
|
|
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_add(Image_Entry *im)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (im->flags.dirty) return;
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_activ_del(im);
|
|
|
|
_evas_cache2_image_lru_del(im);
|
|
|
|
// _evas_cache2_image_lru_nodata_del(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
im->flags.dirty = 1;
|
|
|
|
im->flags.cached = 1;
|
|
|
|
im->cache2->dirty = eina_inlist_prepend(im->cache2->dirty, EINA_INLIST_GET(im));
|
|
|
|
if (im->cache_key)
|
|
|
|
{
|
|
|
|
eina_stringshare_del(im->cache_key);
|
|
|
|
im->cache_key = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_del(Image_Entry *im)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (!im->flags.dirty) return;
|
|
|
|
if (!im->cache2) return;
|
|
|
|
im->flags.dirty = 0;
|
|
|
|
im->flags.cached = 0;
|
|
|
|
im->cache2->dirty = eina_inlist_remove(im->cache2->dirty, EINA_INLIST_GET(im));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_activ_add(Image_Entry *im)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (im->flags.activ) return;
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_del(im);
|
|
|
|
_evas_cache2_image_lru_del(im);
|
|
|
|
// _evas_cache2_image_lru_nodata_del(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
if (!im->cache_key) return;
|
|
|
|
im->flags.activ = 1;
|
|
|
|
im->flags.cached = 1;
|
|
|
|
eina_hash_direct_add(im->cache2->activ, im->cache_key, im);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_activ_del(Image_Entry *im)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (!im->flags.activ) return;
|
|
|
|
if (!im->cache_key) return;
|
|
|
|
im->flags.activ = 0;
|
|
|
|
im->flags.cached = 0;
|
|
|
|
eina_hash_del(im->cache2->activ, im->cache_key, im);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_lru_add(Image_Entry *im)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (im->flags.lru) return;
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_del(im);
|
|
|
|
_evas_cache2_image_activ_del(im);
|
|
|
|
// _evas_cache2_image_lru_nodata_del(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
if (!im->cache_key) return;
|
|
|
|
im->flags.lru = 1;
|
|
|
|
im->flags.cached = 1;
|
|
|
|
eina_hash_direct_add(im->cache2->inactiv, im->cache_key, im);
|
|
|
|
im->cache2->lru = eina_inlist_prepend(im->cache2->lru, EINA_INLIST_GET(im));
|
|
|
|
im->cache2->usage += im->cache2->func.mem_size_get(im);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_lru_del(Image_Entry *im)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (!im->flags.lru) return;
|
|
|
|
if (!im->cache_key) return;
|
|
|
|
im->flags.lru = 0;
|
|
|
|
im->flags.cached = 0;
|
|
|
|
eina_hash_del(im->cache2->inactiv, im->cache_key, im);
|
|
|
|
im->cache2->lru = eina_inlist_remove(im->cache2->lru, EINA_INLIST_GET(im));
|
|
|
|
im->cache2->usage -= im->cache2->func.mem_size_get(im);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_lru_nodata_add(Image_Entry *im)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (im->flags.lru_nodata) return;
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_del(im);
|
|
|
|
_evas_cache2_image_activ_del(im);
|
|
|
|
_evas_cache2_image_lru_del(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
im->flags.lru = 1;
|
|
|
|
im->flags.cached = 1;
|
|
|
|
im->cache2->lru_nodata = eina_inlist_prepend(im->cache2->lru_nodata, EINA_INLIST_GET(im));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_lru_nodata_del(Image_Entry *im)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (!im->flags.lru_nodata) return;
|
|
|
|
im->flags.lru = 0;
|
|
|
|
im->flags.cached = 0;
|
|
|
|
im->cache2->lru_nodata = eina_inlist_remove(im->cache2->lru_nodata, EINA_INLIST_GET(im));
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_timestamp_compare(Image_Timestamp *tstamp, struct stat *st)
|
|
|
|
{
|
|
|
|
if (tstamp->mtime != st->st_mtime) return EINA_FALSE;
|
|
|
|
if (tstamp->size != st->st_size) return EINA_FALSE;
|
|
|
|
if (tstamp->ino != st->st_ino) return EINA_FALSE;
|
|
|
|
#ifdef _STAT_VER_LINUX
|
|
|
|
#if (defined __USE_MISC && defined st_mtime)
|
|
|
|
if (tstamp->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec)
|
|
|
|
return EINA_FALSE;
|
|
|
|
#else
|
|
|
|
if (tstamp->mtime_nsec != (unsigned long int)st->st_mtimensec)
|
|
|
|
return EINA_FALSE;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_timestamp_build(Image_Timestamp *tstamp, struct stat *st)
|
|
|
|
{
|
|
|
|
tstamp->mtime = st->st_mtime;
|
|
|
|
tstamp->size = st->st_size;
|
|
|
|
tstamp->ino = st->st_ino;
|
|
|
|
#ifdef _STAT_VER_LINUX
|
|
|
|
#if (defined __USE_MISC && defined st_mtime)
|
|
|
|
tstamp->mtime_nsec = (unsigned long int)st->st_mtim.tv_nsec;
|
|
|
|
#else
|
|
|
|
tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(Evas_Cache2 *cache, Image_Entry *ie)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
if (!ie) return;
|
|
|
|
|
|
|
|
if (ie->flags.delete_me == 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ie->preload_rid)
|
|
|
|
{
|
|
|
|
ie->flags.delete_me = 1;
|
|
|
|
_evas_cache2_image_entry_preload_remove(ie, NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_del(ie);
|
|
|
|
_evas_cache2_image_activ_del(ie);
|
|
|
|
_evas_cache2_image_lru_del(ie);
|
|
|
|
// _evas_cache2_image_lru_nodata_del(ie);
|
2012-05-03 14:01:31 -07:00
|
|
|
|
|
|
|
|
|
|
|
if (ie->data1)
|
|
|
|
{
|
|
|
|
evas_cserve2_image_unload(ie);
|
|
|
|
evas_cache2_image_unload_data(ie);
|
|
|
|
evas_cserve2_image_free(ie);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (cache)
|
|
|
|
cache->func.surface_delete(ie);
|
|
|
|
}
|
|
|
|
|
|
|
|
FREESTRC(ie->cache_key);
|
|
|
|
FREESTRC(ie->file);
|
|
|
|
FREESTRC(ie->key);
|
|
|
|
ie->cache2 = NULL;
|
|
|
|
|
|
|
|
evas_common_rgba_image_scalecache_shutdown(ie);
|
|
|
|
|
|
|
|
free(ie);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Image_Entry *
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_new(Evas_Cache2 *cache,
|
2012-05-03 14:01:31 -07:00
|
|
|
const char *hkey,
|
|
|
|
Image_Timestamp *tstamp,
|
|
|
|
const char *file,
|
|
|
|
const char *key,
|
2013-05-06 18:50:57 -07:00
|
|
|
Evas_Image_Load_Opts *lo,
|
2012-05-03 14:01:31 -07:00
|
|
|
int *error)
|
|
|
|
{
|
|
|
|
Image_Entry *ie;
|
|
|
|
RGBA_Image *im;
|
|
|
|
|
|
|
|
// ie = cache->func.alloc();
|
|
|
|
im = calloc(1, sizeof(RGBA_Image));
|
|
|
|
if (!im)
|
|
|
|
{
|
2013-07-03 23:13:20 -07:00
|
|
|
if (error)
|
|
|
|
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
|
2012-05-03 14:01:31 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
im->flags = RGBA_IMAGE_NOTHING;
|
|
|
|
evas_common_rgba_image_scalecache_init(&im->cache_entry);
|
|
|
|
|
|
|
|
ie = &im->cache_entry;
|
|
|
|
|
|
|
|
ie->cache2 = cache;
|
|
|
|
if (hkey) ie->cache_key = eina_stringshare_add(hkey);
|
|
|
|
ie->flags.need_data = 1;
|
|
|
|
ie->space = EVAS_COLORSPACE_ARGB8888;
|
|
|
|
ie->w = -1;
|
|
|
|
ie->h = -1;
|
|
|
|
ie->scale = 1;
|
|
|
|
if (file) ie->file = eina_stringshare_add(file);
|
|
|
|
if (key) ie->key = eina_stringshare_add(key);
|
|
|
|
if (tstamp) ie->tstamp = *tstamp;
|
|
|
|
else memset(&ie->tstamp, 0, sizeof(Image_Timestamp));
|
|
|
|
|
|
|
|
if (lo) ie->load_opts = *lo;
|
|
|
|
if (ie->file)
|
|
|
|
{
|
2013-07-02 23:49:59 -07:00
|
|
|
if (!evas_cserve2_image_load(ie))
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
ERR("couldn't load '%s' '%s' with cserve2!",
|
|
|
|
ie->file, ie->key ? ie->key : "");
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(cache, ie);
|
2013-07-03 23:13:20 -07:00
|
|
|
if (error)
|
|
|
|
*error = EVAS_LOAD_ERROR_GENERIC;
|
2012-05-03 14:01:31 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
if (ie->cache_key) _evas_cache2_image_activ_add(ie);
|
|
|
|
else _evas_cache2_image_dirty_add(ie);
|
2013-07-03 23:13:20 -07:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
*error = EVAS_LOAD_ERROR_NONE;
|
2012-05-03 14:01:31 -07:00
|
|
|
return ie;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
evas_cache2_image_surface_alloc(Image_Entry *ie, int w, int h)
|
|
|
|
{
|
|
|
|
Evas_Cache2 *cache = ie->cache2;
|
|
|
|
int wmin = w > 0 ? w : 1;
|
|
|
|
int hmin = h > 0 ? h : 1;
|
|
|
|
|
|
|
|
if (cache->func.surface_alloc(ie, wmin, hmin))
|
|
|
|
{
|
|
|
|
wmin = 0;
|
|
|
|
hmin = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ie->w = wmin;
|
|
|
|
ie->h = hmin;
|
|
|
|
ie->allocated.w = wmin;
|
|
|
|
ie->allocated.h = hmin;
|
|
|
|
ie->flags.loaded = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_evas_cache2_image_preloaded_cb(void *data, Eina_Bool success)
|
|
|
|
{
|
|
|
|
Image_Entry *ie = data;
|
|
|
|
Evas_Cache_Target *tmp;
|
|
|
|
|
|
|
|
ie->cache2->preload = eina_list_remove(ie->cache2->preload, ie);
|
|
|
|
ie->flags.preload_done = success;
|
2013-10-29 03:06:33 -07:00
|
|
|
ie->flags.updated_data = EINA_TRUE;
|
2012-05-03 14:01:31 -07:00
|
|
|
|
|
|
|
while ((tmp = ie->targets))
|
|
|
|
{
|
|
|
|
ie->targets = (Evas_Cache_Target *)
|
|
|
|
eina_inlist_remove(EINA_INLIST_GET(ie->targets),
|
|
|
|
EINA_INLIST_GET(ie->targets));
|
|
|
|
if (!ie->flags.delete_me)
|
|
|
|
evas_object_inform_call_image_preloaded((Evas_Object *) tmp->target);
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ie->flags.delete_me)
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(ie->cache2, ie);
|
2012-05-03 14:01:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_evas_cache2_image_entry_preload_add(Image_Entry *ie, const void *target)
|
|
|
|
{
|
|
|
|
Evas_Cache_Target *tg;
|
|
|
|
|
|
|
|
if (ie->flags.preload_done)
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
|
|
|
tg = malloc(sizeof(Evas_Cache_Target));
|
|
|
|
if (!tg)
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
|
|
|
tg->target = target;
|
|
|
|
ie->targets = (Evas_Cache_Target *)
|
|
|
|
eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
|
|
|
|
|
|
|
|
if (!ie->preload_rid)
|
|
|
|
{
|
|
|
|
ie->cache2->preload = eina_list_append(ie->cache2->preload, ie);
|
|
|
|
evas_cserve2_image_preload(ie, _evas_cache2_image_preloaded_cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_evas_cache2_image_entry_preload_remove(Image_Entry *ie, const void *target)
|
|
|
|
{
|
|
|
|
if (target)
|
|
|
|
{
|
|
|
|
Evas_Cache_Target *tg;
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(ie->targets, tg)
|
|
|
|
{
|
|
|
|
if (tg->target == target)
|
|
|
|
{
|
|
|
|
ie->targets = (Evas_Cache_Target *)
|
|
|
|
eina_inlist_remove(EINA_INLIST_GET(ie->targets),
|
|
|
|
EINA_INLIST_GET(tg));
|
|
|
|
free(tg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Evas_Cache_Target *tg;
|
|
|
|
|
|
|
|
while (ie->targets)
|
|
|
|
{
|
|
|
|
tg = ie->targets;
|
|
|
|
ie->targets = (Evas_Cache_Target *)
|
|
|
|
eina_inlist_remove(EINA_INLIST_GET(ie->targets),
|
|
|
|
EINA_INLIST_GET(tg));
|
|
|
|
free(tg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Should also send message to the server to cancel the request.
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Image_Entry *
|
|
|
|
evas_cache2_image_copied_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
|
|
|
|
{
|
|
|
|
Image_Entry *im;
|
|
|
|
|
|
|
|
if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
|
|
|
|
(cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
|
|
|
|
(cspace == EVAS_COLORSPACE_YCBCR422601_PL))
|
|
|
|
w &= ~0x1;
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
im = _evas_cache2_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
|
2012-05-03 14:01:31 -07:00
|
|
|
if (!im)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
im->space = cspace;
|
|
|
|
im->flags.alpha = alpha;
|
|
|
|
evas_cache2_image_surface_alloc(im, w, h);
|
|
|
|
if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
|
|
|
|
{
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(cache, im);
|
2012-05-03 14:01:31 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
im->references = 1;
|
|
|
|
im->flags.loaded = EINA_TRUE;
|
|
|
|
if (cache->func.debug) cache->func.debug("copied-data", im);
|
|
|
|
|
|
|
|
return im;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Image_Entry *
|
|
|
|
evas_cache2_image_data(Evas_Cache2 *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
|
|
|
|
{
|
|
|
|
Image_Entry *im;
|
|
|
|
|
|
|
|
if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
|
|
|
|
(cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
|
|
|
|
(cspace == EVAS_COLORSPACE_YCBCR422601_PL))
|
|
|
|
w &= ~0x1;
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
im = _evas_cache2_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
|
2012-05-03 14:01:31 -07:00
|
|
|
if (!im) return NULL;
|
|
|
|
im->w = w;
|
|
|
|
im->h = h;
|
|
|
|
im->flags.alpha = alpha;
|
|
|
|
if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
|
|
|
|
{
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(cache, im);
|
2012-05-03 14:01:31 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
im->references = 1;
|
2013-01-09 13:36:03 -08:00
|
|
|
im->flags.loaded = EINA_TRUE;
|
2012-05-03 14:01:31 -07:00
|
|
|
if (cache->func.debug) cache->func.debug("data", im);
|
|
|
|
return im;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Image_Entry *
|
|
|
|
evas_cache2_image_empty(Evas_Cache2 *cache)
|
|
|
|
{
|
|
|
|
Image_Entry *im;
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
im = _evas_cache2_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
|
2012-05-03 14:01:31 -07:00
|
|
|
if (!im)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
im->references = 1;
|
|
|
|
return im;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Image_Entry *
|
|
|
|
evas_cache2_image_size_set(Image_Entry *im, unsigned int w, unsigned h)
|
|
|
|
{
|
|
|
|
Evas_Cache2 *cache;
|
|
|
|
Image_Entry *im2 = NULL;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
|
|
|
|
(im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
|
|
|
|
(im->space == EVAS_COLORSPACE_YCBCR422601_PL))
|
|
|
|
w &= ~0x1;
|
|
|
|
|
|
|
|
if ((im->w == w) && (im->h == h)) return im;
|
|
|
|
|
|
|
|
cache = im->cache2;
|
2013-08-26 03:59:24 -07:00
|
|
|
im2 = _evas_cache2_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL,
|
2012-05-03 14:01:31 -07:00
|
|
|
NULL);
|
|
|
|
if (!im2) goto on_error;
|
|
|
|
|
|
|
|
im2->flags.alpha = im->flags.alpha;
|
|
|
|
im2->space = im->space;
|
|
|
|
im2->load_opts = im->load_opts;
|
|
|
|
evas_cache2_image_surface_alloc(im2, w, h);
|
|
|
|
error = cache->func.size_set(im2, im, w, h);
|
|
|
|
if (error != 0) goto on_error;
|
|
|
|
|
|
|
|
im2->references = 1;
|
2013-01-09 13:36:03 -08:00
|
|
|
im2->flags.loaded = EINA_TRUE;
|
2012-05-03 14:01:31 -07:00
|
|
|
|
|
|
|
evas_cache2_image_close(im);
|
|
|
|
return im2;
|
|
|
|
|
|
|
|
on_error:
|
|
|
|
if (im2)
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(cache, im2);
|
2012-05-03 14:01:31 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Evas_Cache2 *
|
|
|
|
evas_cache2_init(const Evas_Cache2_Image_Func *cb)
|
|
|
|
{
|
2013-06-26 00:31:38 -07:00
|
|
|
char *env;
|
2012-05-03 14:01:31 -07:00
|
|
|
Evas_Cache2 *cache = calloc(1, sizeof(Evas_Cache2));
|
|
|
|
|
|
|
|
cache->func = *cb;
|
|
|
|
cache->activ = eina_hash_string_superfast_new(NULL);
|
|
|
|
cache->inactiv = eina_hash_string_superfast_new(NULL);
|
|
|
|
|
2013-06-26 00:31:38 -07:00
|
|
|
env = getenv("EVAS_CSERVE2_SIZE");
|
|
|
|
if (env)
|
|
|
|
cache->limit = atoi(env) * 1024 * 1024;
|
|
|
|
if (!env || (cache->limit < 0))
|
|
|
|
cache->limit = DEFAULT_CACHE_LRU_SIZE;
|
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
return cache;
|
|
|
|
}
|
|
|
|
|
2012-05-11 13:12:56 -07:00
|
|
|
static Eina_Bool
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_free_cb(EINA_UNUSED const Eina_Hash *hash, EINA_UNUSED const void *key, void *data, void *fdata)
|
2012-05-11 13:12:56 -07:00
|
|
|
{
|
|
|
|
Eina_List **delete_list = fdata;
|
|
|
|
*delete_list = eina_list_prepend(*delete_list, data);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
EAPI void
|
|
|
|
evas_cache2_shutdown(Evas_Cache2 *cache)
|
|
|
|
{
|
2012-05-11 13:12:56 -07:00
|
|
|
Eina_List *delete_list;
|
|
|
|
Image_Entry *im;
|
2013-10-29 22:57:52 -07:00
|
|
|
Eina_Inlist *il;
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH_SAFE(cache->lru, il, im)
|
|
|
|
_evas_cache2_image_entry_delete(cache, im);
|
2012-05-11 13:12:56 -07:00
|
|
|
|
2013-10-29 23:16:21 -07:00
|
|
|
if (cache->lru)
|
|
|
|
ERR("Cache2 LRU still contains %d elements after dump!",
|
|
|
|
eina_inlist_count(cache->lru));
|
|
|
|
|
2012-05-11 13:12:56 -07:00
|
|
|
/* This is mad, I am about to destroy image still alive, but we need to prevent leak. */
|
2013-10-29 22:57:52 -07:00
|
|
|
EINA_INLIST_FOREACH_SAFE(cache->dirty, il, im)
|
|
|
|
_evas_cache2_image_entry_delete(cache, im);
|
2012-05-11 13:12:56 -07:00
|
|
|
|
2013-10-29 23:16:21 -07:00
|
|
|
if (cache->dirty)
|
|
|
|
ERR("Cache2 dirty pool still contains %d elements after dump!",
|
|
|
|
eina_inlist_count(cache->dirty));
|
|
|
|
|
2012-05-11 13:12:56 -07:00
|
|
|
delete_list = NULL;
|
2013-08-26 03:59:24 -07:00
|
|
|
eina_hash_foreach(cache->activ, _evas_cache2_image_free_cb, &delete_list);
|
2013-10-29 22:57:52 -07:00
|
|
|
EINA_LIST_FREE(delete_list, im)
|
|
|
|
_evas_cache2_image_entry_delete(cache, im);
|
2012-05-11 13:12:56 -07:00
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
eina_hash_free(cache->activ);
|
|
|
|
eina_hash_free(cache->inactiv);
|
|
|
|
|
2013-10-29 23:16:21 -07:00
|
|
|
if (cache->usage > 0)
|
|
|
|
WRN("Cache2 reports %d bytes used after shutdown.", cache->usage);
|
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
free(cache);
|
|
|
|
}
|
|
|
|
|
2013-09-02 02:53:18 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
evas_cache2_image_cached(Image_Entry *ie)
|
|
|
|
{
|
|
|
|
if (!ie) return EINA_FALSE;
|
|
|
|
return (ie->cache2 != NULL);
|
|
|
|
}
|
|
|
|
|
2013-07-31 04:29:41 -07:00
|
|
|
EAPI void
|
|
|
|
evas_cache2_image_cache_key_create(char *hkey, const char *path, size_t pathlen,
|
|
|
|
const char *key, size_t keylen,
|
|
|
|
const Evas_Image_Load_Opts *lo)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
const char *ckey = "(null)";
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
/* generate hkey from file+key+load opts */
|
|
|
|
memcpy(hkey, path, pathlen);
|
|
|
|
size = pathlen;
|
|
|
|
memcpy(hkey + size, "//://", 5);
|
|
|
|
size += 5;
|
|
|
|
if (key) ckey = key;
|
2013-07-31 04:29:41 -07:00
|
|
|
else keylen = 6;
|
2012-05-03 14:01:31 -07:00
|
|
|
memcpy(hkey + size, ckey, keylen);
|
|
|
|
size += keylen;
|
|
|
|
if (lo)
|
|
|
|
{
|
|
|
|
memcpy(hkey + size, "//@/", 4);
|
|
|
|
size += 4;
|
|
|
|
size += eina_convert_xtoa(lo->scale_down_by, hkey + size);
|
|
|
|
hkey[size] = '/';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_dtoa(lo->dpi, hkey + size);
|
|
|
|
hkey[size] = '/';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->w, hkey + size);
|
|
|
|
hkey[size] = 'x';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->h, hkey + size);
|
|
|
|
hkey[size] = '/';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->region.x, hkey + size);
|
|
|
|
hkey[size] = '+';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->region.y, hkey + size);
|
|
|
|
hkey[size] = '.';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->region.w, hkey + size);
|
|
|
|
hkey[size] = 'x';
|
|
|
|
size += 1;
|
2012-11-27 10:23:25 -08:00
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
size += eina_convert_xtoa(lo->region.h, hkey + size);
|
2012-11-27 10:23:25 -08:00
|
|
|
hkey[size++] = '!';
|
|
|
|
hkey[size++] = '(';
|
|
|
|
|
|
|
|
hkey[size] = '[';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->scale_load.src_x, hkey + size);
|
|
|
|
hkey[size] = ',';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->scale_load.src_y, hkey + size);
|
|
|
|
hkey[size] = ':';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->scale_load.src_w, hkey + size);
|
|
|
|
hkey[size] = 'x';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->scale_load.src_h, hkey + size);
|
|
|
|
hkey[size++] = ']';
|
|
|
|
|
|
|
|
hkey[size++] = '-';
|
|
|
|
|
|
|
|
hkey[size] = '[';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->scale_load.dst_w, hkey + size);
|
|
|
|
hkey[size] = 'x';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->scale_load.dst_h, hkey + size);
|
|
|
|
hkey[size] = ':';
|
|
|
|
size += 1;
|
|
|
|
size += eina_convert_xtoa(lo->scale_load.smooth, hkey + size);
|
|
|
|
hkey[size++] = ']';
|
|
|
|
|
|
|
|
hkey[size++] = ')';
|
2012-05-03 14:01:31 -07:00
|
|
|
|
|
|
|
if (lo->orientation)
|
|
|
|
{
|
|
|
|
hkey[size] = '/';
|
|
|
|
size += 1;
|
|
|
|
hkey[size] = 'o';
|
|
|
|
size += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hkey[size] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Image_Entry *
|
2013-07-31 04:29:41 -07:00
|
|
|
evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key,
|
|
|
|
Evas_Image_Load_Opts *lo, int *error)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
size_t size;
|
|
|
|
size_t pathlen;
|
|
|
|
size_t keylen;
|
|
|
|
char *hkey;
|
|
|
|
Image_Entry *im;
|
|
|
|
int stat_done = 0, stat_failed = 0;
|
|
|
|
struct stat st;
|
|
|
|
Image_Timestamp tstamp;
|
2013-05-06 18:50:57 -07:00
|
|
|
Evas_Image_Load_Opts prevent;
|
2012-05-03 14:01:31 -07:00
|
|
|
|
2013-10-28 21:54:15 -07:00
|
|
|
if (!path)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
*error = EVAS_LOAD_ERROR_GENERIC;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-05-06 18:50:57 -07:00
|
|
|
memset(&prevent, 0, sizeof (Evas_Image_Load_Opts));
|
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
pathlen = strlen(path);
|
|
|
|
keylen = key ? strlen(key) : 6;
|
2012-11-27 10:23:25 -08:00
|
|
|
size = pathlen + keylen + HKEY_LOAD_OPTS_STR_LEN;
|
2012-05-03 14:01:31 -07:00
|
|
|
hkey = alloca(sizeof(char) * size);
|
|
|
|
|
2013-07-31 04:29:41 -07:00
|
|
|
evas_cache2_image_cache_key_create(hkey, path, pathlen, key, keylen, lo);
|
2012-05-03 14:01:31 -07:00
|
|
|
DBG("Looking at the hash for key '%s'", hkey);
|
|
|
|
|
|
|
|
/* use local var to copy default load options to the image entry */
|
|
|
|
if ((!lo) ||
|
|
|
|
(lo &&
|
|
|
|
(lo->scale_down_by == 0) &&
|
|
|
|
(lo->dpi == 0.0) &&
|
|
|
|
((lo->w == 0) || (lo->h == 0)) &&
|
|
|
|
((lo->region.w == 0) || (lo->region.h == 0)) &&
|
2012-11-27 10:23:25 -08:00
|
|
|
((lo->scale_load.dst_w == 0) || (lo->scale_load.dst_h == 0)) &&
|
2012-05-03 14:01:31 -07:00
|
|
|
(lo->orientation == 0)
|
|
|
|
))
|
|
|
|
{
|
|
|
|
lo = &prevent;
|
|
|
|
}
|
|
|
|
|
|
|
|
im = eina_hash_find(cache->activ, hkey);
|
|
|
|
|
|
|
|
if (im)
|
|
|
|
{
|
|
|
|
int ok = 1;
|
|
|
|
DBG("Found entry on active hash for key: '%s'", hkey);
|
|
|
|
|
|
|
|
stat_done = 1;
|
|
|
|
if (stat(path, &st) < 0)
|
|
|
|
{
|
|
|
|
stat_failed = 1;
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
|
|
|
|
if (ok) goto on_ok;
|
|
|
|
/* image we found doesn't match what's on disk (stat info wise)
|
|
|
|
* so dirty the active cache entry so we never find it again. this
|
|
|
|
* also implicitly guarantees that we only have 1 active copy
|
|
|
|
* of an image at a given key. we wither find it and keep re-reffing
|
|
|
|
* it or we dirty it and get it out */
|
|
|
|
DBG("Entry on inactive hash was invalid (file changed or deleted).");
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_add(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
im = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
im = eina_hash_find(cache->inactiv, hkey);
|
|
|
|
|
|
|
|
if (im)
|
|
|
|
{
|
|
|
|
int ok = 1;
|
|
|
|
DBG("Found entry on inactive hash for key: '%s'", hkey);
|
|
|
|
|
|
|
|
if (!stat_done)
|
|
|
|
{
|
|
|
|
stat_done = 1;
|
|
|
|
if (stat(path, &st) < 0)
|
|
|
|
{
|
|
|
|
stat_failed = 1;
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
|
|
|
|
}
|
|
|
|
else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
/* remove from lru and make it active again */
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_lru_del(im);
|
|
|
|
_evas_cache2_image_activ_add(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
goto on_ok;
|
|
|
|
}
|
|
|
|
DBG("Entry on inactive hash was invalid (file changed or deleted).");
|
|
|
|
/* as avtive cache find - if we match in lru and its invalid, dirty */
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_add(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
/* this image never used, so it have to be deleted */
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(cache, im);
|
2012-05-03 14:01:31 -07:00
|
|
|
im = NULL;
|
|
|
|
}
|
|
|
|
if (stat_failed) goto on_stat_error;
|
|
|
|
|
|
|
|
if (!stat_done)
|
|
|
|
{
|
|
|
|
if (stat(path, &st) < 0) goto on_stat_error;
|
|
|
|
}
|
|
|
|
_timestamp_build(&tstamp, &st);
|
|
|
|
DBG("Creating a new entry for key '%s'.", hkey);
|
2013-08-26 03:59:24 -07:00
|
|
|
im = _evas_cache2_image_entry_new(cache, hkey, &tstamp, path, key,
|
2012-05-03 14:01:31 -07:00
|
|
|
lo, error);
|
|
|
|
if (!im) goto on_stat_error;
|
|
|
|
|
|
|
|
on_ok:
|
|
|
|
*error = EVAS_LOAD_ERROR_NONE;
|
|
|
|
DBG("Using entry on hash for key '%s'", hkey);
|
|
|
|
|
|
|
|
im->references++;
|
|
|
|
|
|
|
|
return im;
|
|
|
|
|
|
|
|
on_stat_error:
|
|
|
|
#ifndef _WIN32
|
|
|
|
if ((errno == ENOENT) || (errno == ENOTDIR) ||
|
|
|
|
(errno == ENAMETOOLONG) || (errno == ELOOP))
|
|
|
|
#else
|
|
|
|
if (errno == ENOENT)
|
|
|
|
#endif
|
|
|
|
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
|
|
|
|
#ifndef _WIN32
|
|
|
|
else if ((errno == ENOMEM) || (errno == EOVERFLOW))
|
|
|
|
#else
|
|
|
|
else if (errno == ENOMEM)
|
|
|
|
#endif
|
|
|
|
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
|
|
|
|
else if (errno == EACCES)
|
|
|
|
*error = EVAS_LOAD_ERROR_PERMISSION_DENIED;
|
|
|
|
else
|
|
|
|
*error = EVAS_LOAD_ERROR_GENERIC;
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
if (im) _evas_cache2_image_entry_delete(cache, im);
|
2012-05-03 14:01:31 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
|
|
|
evas_cache2_image_open_wait(Image_Entry *im)
|
|
|
|
{
|
|
|
|
DBG("Wait for open image '%s' '%s'", im->file, im->key);
|
|
|
|
if (evas_cserve2_image_load_wait(im) != CSERVE2_NONE)
|
|
|
|
return EVAS_LOAD_ERROR_GENERIC;
|
|
|
|
|
|
|
|
return EVAS_LOAD_ERROR_NONE;
|
|
|
|
}
|
|
|
|
|
2012-11-27 10:23:25 -08:00
|
|
|
static Image_Entry *
|
2013-09-23 01:51:06 -07:00
|
|
|
_scaled_image_find(Image_Entry *im, int src_x, int src_y, int src_w,
|
|
|
|
int src_h, int dst_w, int dst_h, int smooth)
|
2012-11-27 10:23:25 -08:00
|
|
|
{
|
|
|
|
size_t pathlen, keylen, size;
|
|
|
|
char *hkey;
|
2013-05-06 18:50:57 -07:00
|
|
|
Evas_Image_Load_Opts lo;
|
2012-11-27 10:23:25 -08:00
|
|
|
Image_Entry *ret;
|
|
|
|
|
|
|
|
if (((!im->file) || ((!im->file) && (!im->key))) || (!im->data1) ||
|
|
|
|
((src_w == dst_w) && (src_h == dst_h)) ||
|
|
|
|
((!im->flags.alpha) && (!smooth))) return NULL;
|
|
|
|
|
|
|
|
pathlen = strlen(im->file);
|
|
|
|
keylen = im->key ? strlen(im->key) : 6;
|
|
|
|
size = pathlen + keylen + HKEY_LOAD_OPTS_STR_LEN;
|
|
|
|
hkey = alloca(sizeof(char) * size);
|
|
|
|
|
|
|
|
memcpy(&lo, &im->load_opts, sizeof lo);
|
|
|
|
lo.scale_load.src_x = src_x;
|
|
|
|
lo.scale_load.src_y = src_y;
|
|
|
|
lo.scale_load.src_w = src_w;
|
|
|
|
lo.scale_load.src_h = src_h;
|
|
|
|
lo.scale_load.dst_w = dst_w;
|
|
|
|
lo.scale_load.dst_h = dst_h;
|
|
|
|
lo.scale_load.smooth = smooth;
|
|
|
|
|
|
|
|
if (!smooth)
|
|
|
|
{
|
|
|
|
lo.scale_load.smooth = 1;
|
2013-07-31 04:29:41 -07:00
|
|
|
evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
|
|
|
|
im->key, keylen, &lo);
|
2012-11-27 10:23:25 -08:00
|
|
|
|
|
|
|
ret = eina_hash_find(im->cache2->activ, hkey);
|
|
|
|
if (ret) goto found;
|
|
|
|
|
|
|
|
ret = eina_hash_find(im->cache2->inactiv, hkey);
|
|
|
|
if (ret) goto handle_inactiv;
|
|
|
|
|
|
|
|
lo.scale_load.smooth = smooth;
|
|
|
|
}
|
|
|
|
|
2013-07-31 04:29:41 -07:00
|
|
|
evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
|
|
|
|
im->key, keylen, &lo);
|
2012-11-27 10:23:25 -08:00
|
|
|
|
|
|
|
ret = eina_hash_find(im->cache2->activ, hkey);
|
|
|
|
if (ret) goto found;
|
|
|
|
|
|
|
|
ret = eina_hash_find(im->cache2->inactiv, hkey);
|
|
|
|
|
|
|
|
handle_inactiv:
|
|
|
|
if (!ret) return NULL;
|
|
|
|
|
|
|
|
/* Remove from lru and make it active again */
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_lru_del(ret);
|
|
|
|
_evas_cache2_image_activ_add(ret);
|
2012-11-27 10:23:25 -08:00
|
|
|
|
|
|
|
found:
|
2013-01-09 13:40:25 -08:00
|
|
|
ret->references++;
|
|
|
|
|
2012-11-27 10:23:25 -08:00
|
|
|
evas_cache2_image_load_data(ret);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Image_Entry *
|
2013-07-03 02:18:00 -07:00
|
|
|
evas_cache2_image_scale_load(Image_Entry *im,
|
|
|
|
int src_x, int src_y, int src_w, int src_h,
|
|
|
|
int dst_w, int dst_h, int smooth)
|
2012-11-27 10:23:25 -08:00
|
|
|
{
|
|
|
|
size_t pathlen, keylen, size;
|
|
|
|
char *hkey;
|
2013-05-06 18:50:57 -07:00
|
|
|
Evas_Image_Load_Opts lo;
|
2012-11-27 10:23:25 -08:00
|
|
|
int error = EVAS_LOAD_ERROR_NONE;
|
|
|
|
Image_Entry *ret;
|
|
|
|
|
2013-09-04 00:14:37 -07:00
|
|
|
if (!im->cache2)
|
|
|
|
return im;
|
|
|
|
|
2013-07-03 02:18:00 -07:00
|
|
|
if (!smooth && im->scale_hint != EVAS_IMAGE_SCALE_HINT_STATIC)
|
|
|
|
goto parent_out;
|
|
|
|
|
|
|
|
// Concept from scalecache: don't cache large images.
|
|
|
|
if (((((dst_w > 640) || (dst_h > 640)) &&
|
|
|
|
((dst_w * dst_h) > (480 * 480))) ||
|
|
|
|
(im->scale_hint == EVAS_IMAGE_SCALE_HINT_STATIC)) &&
|
|
|
|
(im->scale_hint != EVAS_IMAGE_SCALE_HINT_DYNAMIC))
|
|
|
|
goto parent_out;
|
|
|
|
|
2012-11-27 10:23:25 -08:00
|
|
|
if (((!im->file) || ((!im->file) && (!im->key))) ||
|
|
|
|
((src_w == 0) || (src_h == 0) || (dst_w == 0) || (dst_h == 0)) ||
|
|
|
|
(im->scale_hint == EVAS_IMAGE_SCALE_HINT_DYNAMIC)) goto parent_out;
|
|
|
|
|
|
|
|
if (((src_w == dst_w) && (src_h == dst_h)) ||
|
|
|
|
((!im->flags.alpha) && (!smooth))) goto parent_out;
|
|
|
|
|
|
|
|
ret = _scaled_image_find(im, src_x, src_y, src_w, src_h,
|
|
|
|
dst_w, dst_h, smooth);
|
|
|
|
if (ret) return ret;
|
|
|
|
|
|
|
|
pathlen = strlen(im->file);
|
|
|
|
keylen = im->key ? strlen(im->key) : 6;
|
|
|
|
size = pathlen + keylen + HKEY_LOAD_OPTS_STR_LEN;
|
|
|
|
hkey = alloca(sizeof(char) * size);
|
|
|
|
|
|
|
|
memcpy(&lo, &im->load_opts, sizeof lo);
|
|
|
|
lo.scale_load.src_x = src_x;
|
|
|
|
lo.scale_load.src_y = src_y;
|
|
|
|
lo.scale_load.src_w = src_w;
|
|
|
|
lo.scale_load.src_h = src_h;
|
|
|
|
lo.scale_load.dst_w = dst_w;
|
|
|
|
lo.scale_load.dst_h = dst_h;
|
|
|
|
lo.scale_load.smooth = smooth;
|
|
|
|
lo.scale_load.scale_hint = im->scale_hint;
|
|
|
|
|
2013-07-31 04:29:41 -07:00
|
|
|
evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
|
|
|
|
im->key, keylen, &lo);
|
2012-11-27 10:23:25 -08:00
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
ret = _evas_cache2_image_entry_new(im->cache2, hkey, NULL, im->file, im->key,
|
2012-11-27 10:23:25 -08:00
|
|
|
&lo, &error);
|
|
|
|
if (error != EVAS_LOAD_ERROR_NONE)
|
|
|
|
{
|
|
|
|
ERR("Failed to create scale image entry with error code %d.", error);
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
if (ret) _evas_cache2_image_entry_delete(im->cache2, ret);
|
2012-11-27 10:23:25 -08:00
|
|
|
goto parent_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
evas_cserve2_image_load_wait(ret);
|
2014-01-12 22:42:14 -08:00
|
|
|
error = evas_cache2_image_load_data(ret);
|
|
|
|
if (error != EVAS_LOAD_ERROR_NONE)
|
|
|
|
{
|
|
|
|
_evas_cache2_image_entry_delete(im->cache2, ret);
|
|
|
|
goto parent_out;
|
|
|
|
}
|
2012-11-27 10:23:25 -08:00
|
|
|
|
|
|
|
ret->references++;
|
|
|
|
ret->w = dst_w;
|
|
|
|
ret->h = dst_h;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
parent_out:
|
|
|
|
evas_cache2_image_load_data(im);
|
|
|
|
|
|
|
|
return im;
|
|
|
|
}
|
|
|
|
|
2012-12-21 13:13:06 -08:00
|
|
|
EAPI void
|
|
|
|
evas_cache2_image_ref(Image_Entry *im)
|
|
|
|
{
|
|
|
|
im->references++;
|
|
|
|
}
|
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
EAPI void
|
|
|
|
evas_cache2_image_close(Image_Entry *im)
|
|
|
|
{
|
|
|
|
Evas_Cache2 *cache;
|
|
|
|
int references;
|
|
|
|
|
|
|
|
im->references--;
|
|
|
|
if (im->references < 0)
|
|
|
|
{
|
|
|
|
ERR("image with negative references: %d", im->references);
|
|
|
|
im->references = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
references = im->references;
|
|
|
|
cache = im->cache2;
|
|
|
|
|
|
|
|
if (references > 0)
|
|
|
|
return;
|
|
|
|
|
2013-09-26 22:46:48 -07:00
|
|
|
if (im->flags.dirty || im->animated.animated)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(cache, im);
|
2012-05-03 14:01:31 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_lru_add(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
if (cache)
|
|
|
|
evas_cache2_flush(cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
|
|
|
evas_cache2_image_load_data(Image_Entry *ie)
|
|
|
|
{
|
|
|
|
int error = EVAS_LOAD_ERROR_NONE;
|
|
|
|
|
2013-04-24 23:05:18 -07:00
|
|
|
if ((ie->flags.loaded) && (!ie->animated.animated))
|
2013-09-08 21:57:45 -07:00
|
|
|
{
|
|
|
|
evas_cserve2_image_hit(ie);
|
|
|
|
return EVAS_LOAD_ERROR_NONE;
|
|
|
|
}
|
2012-05-03 14:01:31 -07:00
|
|
|
|
|
|
|
ie->flags.in_progress = EINA_TRUE;
|
|
|
|
|
|
|
|
DBG("try cserve2 image data '%s' '%s'",
|
|
|
|
ie->file, ie->key ? ie->key : "");
|
|
|
|
if (evas_cserve2_image_data_load(ie))
|
|
|
|
{
|
2013-06-04 03:40:36 -07:00
|
|
|
error = evas_cserve2_image_load_data_wait(ie);
|
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
RGBA_Image *im = (RGBA_Image *)ie;
|
2013-06-04 03:40:36 -07:00
|
|
|
if ((error == CSERVE2_NONE) && im->image.data)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
2013-10-02 04:23:14 -07:00
|
|
|
DBG("try cserve2 image data '%s' '%s' loaded!",
|
|
|
|
ie->file, ie->key ? ie->key : "");
|
2012-05-03 14:01:31 -07:00
|
|
|
error = EVAS_LOAD_ERROR_NONE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("Failed to load data for image '%s' '%s'.",
|
|
|
|
ie->file, ie->key ? ie->key : "");
|
|
|
|
error = EVAS_LOAD_ERROR_GENERIC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("Couldn't send LOAD message to cserve2.");
|
|
|
|
error = EVAS_LOAD_ERROR_GENERIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
ie->flags.in_progress = EINA_FALSE;
|
|
|
|
ie->flags.loaded = 1;
|
|
|
|
|
|
|
|
if (error != EVAS_LOAD_ERROR_NONE)
|
|
|
|
ie->flags.loaded = 0;
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
evas_cache2_image_unload_data(Image_Entry *im)
|
|
|
|
{
|
|
|
|
// FIXME: This function seems pretty useless, since we always have
|
|
|
|
// to send an UNLOAD message to the server when closing an image,
|
|
|
|
// even if we didn't send a LOAD message before, because the SETOPTS
|
|
|
|
// message increases the image refcount.
|
|
|
|
if (im->flags.in_progress)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((!im->file))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!im->flags.loaded)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
evas_cache2_image_preload_data(Image_Entry *im, const void *target)
|
|
|
|
{
|
|
|
|
RGBA_Image *img = (RGBA_Image *)im;
|
|
|
|
|
|
|
|
if ((im->flags.loaded) && (img->image.data))
|
|
|
|
{
|
|
|
|
evas_object_inform_call_image_preloaded((Evas_Object *)target);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_evas_cache2_image_entry_preload_add(im, target))
|
|
|
|
evas_object_inform_call_image_preloaded((Evas_Object *)target);
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
evas_cache2_image_preload_cancel(Image_Entry *im, const void *target)
|
|
|
|
{
|
|
|
|
if (!target)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_evas_cache2_image_entry_preload_remove(im, target);
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI DATA32 *
|
|
|
|
evas_cache2_image_pixels(Image_Entry *im)
|
|
|
|
{
|
|
|
|
return im->cache2->func.surface_pixels(im);
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Image_Entry *
|
|
|
|
evas_cache2_image_writable(Image_Entry *im)
|
|
|
|
{
|
|
|
|
Evas_Cache2 *cache = im->cache2;
|
|
|
|
Image_Entry *im2 = NULL;
|
|
|
|
|
|
|
|
if (!im->cache_key)
|
|
|
|
{
|
|
|
|
if (!im->flags.dirty)
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_add(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
return im;
|
|
|
|
}
|
|
|
|
|
|
|
|
im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
|
|
|
|
evas_cache2_image_pixels(im),
|
|
|
|
im->flags.alpha, im->space);
|
|
|
|
if (!im2)
|
2013-10-28 23:12:58 -07:00
|
|
|
{
|
|
|
|
ERR("Could not create a copy of this image (%dx%d)", im->w, im->h);
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-05-03 14:01:31 -07:00
|
|
|
|
|
|
|
evas_cache2_image_close(im);
|
|
|
|
return im2;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Image_Entry *
|
|
|
|
evas_cache2_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
|
|
|
|
{
|
|
|
|
Evas_Cache2 *cache = im->cache2;
|
|
|
|
Image_Entry *im2 = NULL;
|
|
|
|
|
|
|
|
if (!im->cache_key)
|
|
|
|
{
|
|
|
|
if (!im->flags.dirty)
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_dirty_add(im);
|
2012-05-03 14:01:31 -07:00
|
|
|
im2 = im;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
im2 = evas_cache2_image_copied_data(cache, im->w, im->h,
|
|
|
|
evas_cache2_image_pixels(im),
|
|
|
|
im->flags.alpha, im->space);
|
|
|
|
if (!im2)
|
|
|
|
goto on_error;
|
|
|
|
|
|
|
|
evas_cache2_image_close(im);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cache->func.dirty_region)
|
|
|
|
cache->func.dirty_region(im2, x, y, w, h);
|
|
|
|
|
|
|
|
return im2;
|
|
|
|
|
|
|
|
on_error:
|
|
|
|
evas_cache2_image_close(im);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
|
|
|
evas_cache2_flush(Evas_Cache2 *cache)
|
|
|
|
{
|
2013-10-29 23:16:21 -07:00
|
|
|
Eina_Inlist *cur, *prev;
|
|
|
|
|
2012-05-03 14:01:31 -07:00
|
|
|
if (cache->limit == -1) return -1;
|
2013-10-29 23:16:21 -07:00
|
|
|
if (!cache->lru) return cache->usage; // Should be 0
|
2012-05-03 14:01:31 -07:00
|
|
|
|
2013-10-29 23:16:21 -07:00
|
|
|
//EINA_INLIST_FOREACH_REVERSE_SAFE(cache->lru, cur, prev, im)
|
|
|
|
for (cur = cache->lru->last;
|
|
|
|
cur && (cache->limit < cache->usage);
|
|
|
|
cur = prev)
|
2012-05-03 14:01:31 -07:00
|
|
|
{
|
|
|
|
Image_Entry *im;
|
|
|
|
|
2013-10-29 23:16:21 -07:00
|
|
|
prev = cur->prev;
|
|
|
|
im = EINA_INLIST_CONTAINER_GET(cur, Image_Entry);
|
2013-08-26 03:59:24 -07:00
|
|
|
_evas_cache2_image_entry_delete(cache, im);
|
2012-05-03 14:01:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return cache->usage;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
evas_cache2_limit_set(Evas_Cache2 *cache, int limit)
|
|
|
|
{
|
|
|
|
if (cache->limit == limit)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DBG("Cache2 limit set to %d", limit);
|
|
|
|
|
|
|
|
cache->limit = limit;
|
|
|
|
|
|
|
|
evas_cache2_flush(cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
|
|
|
evas_cache2_limit_get(Evas_Cache2 *cache)
|
|
|
|
{
|
|
|
|
return cache->limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
|
|
|
evas_cache2_usage_get(Evas_Cache2 *cache)
|
|
|
|
{
|
|
|
|
return cache->usage;
|
|
|
|
}
|