diff --git a/legacy/evas/ChangeLog b/legacy/evas/ChangeLog index 2c8459c6af..14223b6293 100644 --- a/legacy/evas/ChangeLog +++ b/legacy/evas/ChangeLog @@ -166,3 +166,9 @@ 2011-03-11 Carsten Haitzler (The Rasterman) * Add ICO loader to evas (also can load CUR cursor files in theory) + +2011-03-14 Carsten Haitzler (The Rasterman) + + * Add "load from memory" API: evas_object_image_memfile_set() by + popular demand. Can load an image format from a memory address. + diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index f3d19b6acf..bf137f5cdd 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -1245,6 +1245,7 @@ typedef void (*Evas_Object_Image_Pixels_Get_Cb) (void *data, Evas_Object *o); EAPI Evas_Object *evas_object_image_add (Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; EAPI Evas_Object *evas_object_image_filled_add (Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; + EAPI void evas_object_image_memfile_set (Evas_Object *obj, void *data, int size, char *format, char *key) EINA_ARG_NONNULL(1, 2); EAPI void evas_object_image_file_set (Evas_Object *obj, const char *file, const char *key) EINA_ARG_NONNULL(1); EAPI void evas_object_image_file_get (const Evas_Object *obj, const char **file, const char **key) EINA_ARG_NONNULL(1, 2); EAPI void evas_object_image_border_set (Evas_Object *obj, int l, int r, int t, int b) EINA_ARG_NONNULL(1); diff --git a/legacy/evas/src/lib/cache/evas_cache_image.c b/legacy/evas/src/lib/cache/evas_cache_image.c index b75261d35b..7998ae36f2 100644 --- a/legacy/evas/src/lib/cache/evas_cache_image.c +++ b/legacy/evas/src/lib/cache/evas_cache_image.c @@ -964,6 +964,7 @@ evas_cache_image_drop(Image_Entry *im) LKL(im->lock_references); #endif im->references--; + if (im->references < 0) im->references = 0; references = im->references; #ifdef EVAS_FRAME_QUEUING LKU(im->lock_references); @@ -1129,7 +1130,7 @@ evas_cache_image_alone(Image_Entry *im) LKU(im->lock_references); #endif - if (references == 1) + if (references <= 1) { if (!(im->flags.dirty)) { diff --git a/legacy/evas/src/lib/canvas/evas_object_image.c b/legacy/evas/src/lib/canvas/evas_object_image.c index 8f715616c5..c4ec7720e0 100644 --- a/legacy/evas/src/lib/canvas/evas_object_image.c +++ b/legacy/evas/src/lib/canvas/evas_object_image.c @@ -1,3 +1,8 @@ +#include +#include +#include +#include + #include "evas_common.h" #include "evas_private.h" #include "../engines/common/evas_convert_color.h" @@ -57,6 +62,9 @@ struct _Evas_Object_Image Evas_Object_Image_Pixels_Get_Cb get_pixels; void *get_pixels_data; } func; + + const char *tmpf; + int tmpf_fd; Evas_Image_Scale_Hint scale_hint; Evas_Image_Content_Hint content_hint; @@ -100,6 +108,7 @@ static void _proxy_unset(Evas_Object *proxy); static void _proxy_set(Evas_Object *proxy, Evas_Object *src); static void _proxy_error(Evas_Object *proxy, void *context, void *output, void *surface, int x, int y); +static void _cleanup_tmpf(Evas_Object *obj); static const Evas_Object_Func object_func = { @@ -179,6 +188,120 @@ evas_object_image_filled_add(Evas *e) return obj; } +static void +_cleanup_tmpf(Evas_Object *obj) +{ + Evas_Object_Image *o; + + o = (Evas_Object_Image *)(obj->object_data); + if (!o->tmpf) return; +#ifdef __linux__ +#else + unlink(o->tmpf); +#endif + if (o->tmpf_fd >= 0) close(o->tmpf_fd); + eina_stringshare_del(o->tmpf); + o->tmpf_fd = -1; + o->tmpf = NULL; +} + +static void +_create_tmpf(Evas_Object *obj, void *data, int size, char *format __UNUSED__) +{ + Evas_Object_Image *o; + char buf[4096]; + void *dst; + int fd = -1; + + o = (Evas_Object_Image *)(obj->object_data); +#ifdef __linux__ + snprintf(buf, sizeof(buf), "/dev/shm/.evas-tmpf-%i-%p-%i-XXXXXX", + (int)getpid(), data, (int)size); + fd = mkstemp(buf); +#endif + if (fd < 0) + { + snprintf(buf, sizeof(buf), "/tmp/.evas-tmpf-%i-%p-%i-XXXXXX", + (int)getpid(), data, (int)size); + fd = mkstemp(buf); + } + if (fd < 0) return; + if (ftruncate(fd, size) < 0) + { + unlink(buf); + close(fd); + return; + } + unlink(buf); + dst = mmap(NULL, size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, 0); + if (dst == MAP_FAILED) + { + close(fd); + return; + } + o->tmpf_fd = fd; +#ifdef __linux__ + snprintf(buf, sizeof(buf), "/proc/%li/fd/%i", (long)getpid(), fd); +#endif + o->tmpf = eina_stringshare_add(buf); + memcpy(dst, data, size); + munmap(dst, size); +} + +/** + * Sets the data for an image from memory to be loaded + * + * This is the same as evas_object_image_file_set() but the file to be loaded + * may exist at an address in memory (the data for the file, not the filename + * itself). The @p data at the address is copied and stored for future use, so + * no @p data needs to be kept after this call is made. It will be managed and + * freed for you when no longer needed. The @p size is limited to 2 gigabytes + * in size, and must be greater than 0. A NULL @p data pointer is also invalid. + * Set the filename to NULL to reset to empty state and have the image file + * data freed from memory using evas_object_image_file_set(). + * + * The @p format is optional (pass NULL if you don't need/use it). It is used + * to help Evas guess better which loader to use for the data. It may simply + * be the "extension" of the file as it would normally be on disk such as + * "jpg" or "png" or "gif" etc. + * + * @param obj The given image object. + * @param data The image file data address + * @param size The size of the image file data in bytes + * @param format The format of the file (optional), or NULL if not needed + * @param key The image key in file, or NULL. + */ +EAPI void +evas_object_image_memfile_set(Evas_Object *obj, void *data, int size, char *format, char *key) +{ + Evas_Object_Image *o; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return; + MAGIC_CHECK_END(); + o = (Evas_Object_Image *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); + return; + MAGIC_CHECK_END(); + _cleanup_tmpf(obj); + evas_object_image_file_set(obj, NULL, NULL); + if ((size < 1) || (!data)) return; + + _create_tmpf(obj, data, size, format); + evas_object_image_file_set(obj, o->tmpf, key); + if (!o->engine_data) + { + _cleanup_tmpf(obj); + return; + } + // invalidate the cache effectively + evas_object_image_alpha_set(obj, !o->cur.has_alpha); + evas_object_image_alpha_set(obj, !o->cur.has_alpha); +} + /** * Sets the filename and key of the given image object. * @@ -202,6 +325,7 @@ evas_object_image_file_set(Evas_Object *obj, const char *file, const char *key) MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); return; MAGIC_CHECK_END(); + if ((o->tmpf) && (file != o->tmpf)) _cleanup_tmpf(obj); if ((o->cur.file) && (file) && (!strcmp(o->cur.file, file))) { if ((!o->cur.key) && (!key)) @@ -1303,7 +1427,7 @@ evas_object_image_alpha_set(Evas_Object *obj, Eina_Bool has_alpha) if (o->engine_data) { int stride = 0; - + #ifdef EVAS_FRAME_QUEUING evas_common_pipe_op_image_flush(o->engine_data); #endif @@ -2659,6 +2783,7 @@ evas_object_image_new(void) o->cur.opaque_valid = 0; o->cur.source = NULL; o->prev = o->cur; + o->tmpf_fd = -1; return o; } @@ -2674,6 +2799,7 @@ evas_object_image_free(Evas_Object *obj) return; MAGIC_CHECK_END(); /* free obj */ + _cleanup_tmpf(obj); if (o->cur.file) eina_stringshare_del(o->cur.file); if (o->cur.key) eina_stringshare_del(o->cur.key); if (o->cur.source) _proxy_unset(obj);