diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index b4a92d1ed4..a1f30d856a 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -744,6 +744,13 @@ typedef enum _Evas_Image_Scale_Hint EVAS_IMAGE_SCALE_HINT_STATIC = 2 /**< Image is not being re-scaled over time, thus turning scaling cache @b on for its data */ } Evas_Image_Scale_Hint; /**< How an image's data is to be treated by Evas, with regard to scaling cache */ +typedef enum _Evas_Image_Animated_Loop_Hint +{ + EVAS_IMAGE_ANIMATED_HINT_NONE = 0, + EVAS_IMAGE_ANIMATED_HINT_LOOP = 1, /**< Image's animation mode is loop like 1->2->3->1->2->3 */ + EVAS_IMAGE_ANIMATED_HINT_PINGPONG = 2 /**< Image's animation mode is pingpong like 1->2->3->2->1-> ... */ +} Evas_Image_Animated_Loop_Hint; + typedef enum _Evas_Engine_Render_Mode { EVAS_RENDER_MODE_BLOCKING = 0, @@ -7088,6 +7095,121 @@ EAPI Eina_Bool evas_object_image_extension_can_load_get(const char *file); */ EAPI Eina_Bool evas_object_image_extension_can_load_fast_get(const char *file); +/** + * Get the animation of an image object. + * + * @param obj Image object + * @return whether obj support animation + * + * This returns the possibility of animation of image object's image + * currently Evas only support animation of gif file type. + * + * Example: + * @code + * extern Evas_Object *object; + * + * + * if (evas_object_image_animated_get(obj)) + * { + * int frame_count; + * int loop_count; + * Evas_Image_Animated_Loop_Hint loop_type; + * double duration; + * + * frame_count = evas_object_image_animated_frame_count_get(obj); + * printf("This image has %d frames\n",frame_count); + * + * duration = evas_object_image_animated_frame_duration_get(obj,1,0); + * printf("Frame 1's duration is %f. You had better set object's frame to 2 after this duration using timer\n"); + * + * loop_count = evas_object_image_animated_loop_count_get(obj); + * printf("loop count is %d. You had better run loop %d times\n",loop_count,loop_count); + * + * loop_type = evas_object_image_animated_loop_type_get(obj); + * if (loop_type == EVAS_IMAGE_ANIMATED_HINT_LOOP) + * printf("You had better set frame like 1->2->3->1->2->3...\n"); + * else if (loop_type == EVAS_IMAGE_ANIMATED_HINT_PINGPONG) + * printf("You had better set frame like 1->2->3->2->1->2...\n"); + * else + * printf("Unknown loop type\n"); + * + * evas_object_image_animated_frame_set(obj,1); + * printf("You set image object's frame to 1. You can see frame 1\n"); + * } + * + * @endcode + */ +EAPI Eina_Bool evas_object_image_animated_get(const Evas_Object *obj); + +/** + * Get the total frame number of image object's file. + * + * @param obj Image object + * @return the number of frame + * + * This returns total frame number of image object's file. + * See @ref evas_object_image_animated_get for more details. + */ +EAPI int evas_object_image_animated_frame_num_get(const Evas_Object *obj); + +/** + * Get the loop type of an animated image object. + * + * @param obj Image object + * @return loop type of animated image object + * + * This returns loop type. + * If Evas_Image_Animated_Loop_Hint is EVAS_IMAGE_ANIMATED_HINT_LOOP, It is better to set sequence like 1->2->3->1->2->3 + * If Evas_Image_Animated_Loop_Hint is EVAS_IMAGE_ANIMATED_HINT_PINGPONG, It is better to set sequence like 1->2->3->2->1->2 + * Default type is EVAS_IMAGE_ANIMATED_HINT_LOOP. + * + * See @ref evas_object_image_animated_get for more details. + */ +EAPI Evas_Image_Animated_Loop_Hint evas_object_image_animated_loop_type_get(const Evas_Object *obj); + +/** + * Get the number of loop of an animated image object. + * + * @param obj Image object + * @return the number of loop of an animated image object + * + * This returns loop count of image. + * Default value is 0. It means infinite loop. + * If loop count is 1, you can set each frame only one time. + * + * See @ref evas_object_image_animated_get for more details. + */ +EAPI int evas_object_image_animated_loop_count_get(const Evas_Object *obj); + +/** + * Get the duration of frames of an image object. + * + * @param obj Image object + * @param start_frame start frame + * @param fram_num number of frames which want to duration + * + * This returns total duration of frames. + * For example. + * If you set start_frame to 1 and frame_num 0, you can frame 1's duration + * If you set start_frame to 1 and frame_num 1, you can frame1 duration + frame2 duration + * + * See @ref evas_object_image_animated_get for more details. + * + */ +EAPI double evas_object_image_animated_frame_duration_get(const Evas_Object *obj, int start_frame, int fram_num); + +/** + * Set the frame to current frame of an image object must render + * + * @param obj The given image object. + * @param frame_num The index of current frame + * + * This set image object's current frame to frame_num. + * If you set frame_num to 5, evas will render frame 5 of image when rendering time + * + * See @ref evas_object_image_animated_get for more details. + */ +EAPI void evas_object_image_animated_frame_set(Evas_Object *obj, int frame_num); /** * @} */ diff --git a/legacy/evas/src/lib/cache/evas_cache_image.c b/legacy/evas/src/lib/cache/evas_cache_image.c index b11f7dae3c..9ba65e793a 100644 --- a/legacy/evas/src/lib/cache/evas_cache_image.c +++ b/legacy/evas/src/lib/cache/evas_cache_image.c @@ -1166,7 +1166,7 @@ evas_cache_image_load_data(Image_Entry *im) #endif int error = EVAS_LOAD_ERROR_NONE; - if (im->flags.loaded) return error; + if ((im->flags.loaded) && (!im->flags.animated)) return error; #ifdef BUILD_ASYNC_PRELOAD if (im->preload) { @@ -1190,7 +1190,7 @@ evas_cache_image_load_data(Image_Entry *im) LKU(wakeup); } - if (im->flags.loaded) return error; + if ((im->flags.loaded) && (!im->flags.animated)) return error; LKL(im->lock); #endif im->flags.in_progress = EINA_TRUE; diff --git a/legacy/evas/src/lib/canvas/evas_object_image.c b/legacy/evas/src/lib/canvas/evas_object_image.c index 520423eaf7..a7126484e9 100644 --- a/legacy/evas/src/lib/canvas/evas_object_image.c +++ b/legacy/evas/src/lib/canvas/evas_object_image.c @@ -37,6 +37,7 @@ struct _Evas_Object_Image Evas_Map *defmap; const char *file; const char *key; + int frame; int cspace; unsigned char smooth_scale : 1; @@ -1858,6 +1859,7 @@ evas_object_image_alpha_mask_set(Evas_Object *obj, Eina_Bool ismask) } +#define FRAME_MAX 1024 EAPI Evas_Image_Content_Hint evas_object_image_content_hint_get(const Evas_Object *obj) { @@ -1873,6 +1875,152 @@ evas_object_image_content_hint_get(const Evas_Object *obj) return o->content_hint; } +/* animated feature */ +EAPI Eina_Bool +evas_object_image_animated_get(const Evas_Object *obj) +{ + Evas_Object_Image *o; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return EINA_FALSE; + MAGIC_CHECK_END(); + o = (Evas_Object_Image *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); + return EINA_FALSE; + MAGIC_CHECK_END(); + + if (obj->layer->evas->engine.func->image_animated_get) + return obj->layer->evas->engine.func->image_animated_get(obj->layer->evas->engine.data.output, o->engine_data); + return EINA_FALSE; +} + +EAPI int +evas_object_image_animated_frame_count_get(const Evas_Object *obj) +{ + Evas_Object_Image *o; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return -1; + MAGIC_CHECK_END(); + o = (Evas_Object_Image *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); + return -1; + MAGIC_CHECK_END(); + + if (!evas_object_image_animated_get(obj)) return -1; + if (obj->layer->evas->engine.func->image_animated_frame_count_get) + return obj->layer->evas->engine.func->image_animated_frame_count_get(obj->layer->evas->engine.data.output, o->engine_data); + return -1; +} + +EAPI Evas_Image_Animated_Loop_Hint +evas_object_image_animated_loop_type_get(const Evas_Object *obj) +{ + Evas_Object_Image *o; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return EVAS_IMAGE_ANIMATED_HINT_NONE; + MAGIC_CHECK_END(); + o = (Evas_Object_Image *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); + return EVAS_IMAGE_ANIMATED_HINT_NONE; + MAGIC_CHECK_END(); + + if (!evas_object_image_animated_get(obj)) return EVAS_IMAGE_ANIMATED_HINT_NONE; + + if (obj->layer->evas->engine.func->image_animated_loop_type_get) + return obj->layer->evas->engine.func->image_animated_loop_type_get(obj->layer->evas->engine.data.output, o->engine_data); + return EVAS_IMAGE_ANIMATED_HINT_NONE; +} + +EAPI int +evas_object_image_animated_loop_count_get(const Evas_Object *obj) +{ + Evas_Object_Image *o; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return -1; + MAGIC_CHECK_END(); + o = (Evas_Object_Image *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); + return -1; + MAGIC_CHECK_END(); + + if (!evas_object_image_animated_get(obj)) return -1; + + if (obj->layer->evas->engine.func->image_animated_loop_count_get) + return obj->layer->evas->engine.func->image_animated_loop_count_get(obj->layer->evas->engine.data.output, o->engine_data); + return -1; +} + +EAPI double +evas_object_image_animated_frame_duration_get(const Evas_Object *obj, int start_frame, int frame_num) +{ + Evas_Object_Image *o; + int frame_count = 0; + + if (start_frame < 1) return -1; + if (frame_num < 0) return -1; + + MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); + return -1; + MAGIC_CHECK_END(); + o = (Evas_Object_Image *)(obj->object_data); + MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); + return -1; + MAGIC_CHECK_END(); + + if (!evas_object_image_animated_get(obj)) return -1; + + if (!obj->layer->evas->engine.func->image_animated_frame_count_get) return -1; + + frame_count = obj->layer->evas->engine.func->image_animated_frame_count_get(obj->layer->evas->engine.data.output, o->engine_data); + + if ((start_frame + frame_num) > frame_count) return -1; + if (obj->layer->evas->engine.func->image_animated_frame_duration_get) + return obj->layer->evas->engine.func->image_animated_frame_duration_get(obj->layer->evas->engine.data.output, o->engine_data, start_frame, frame_num); + return -1; +} + +EAPI void +evas_object_image_animated_frame_set(Evas_Object *obj, int frame_index) +{ + Evas_Object_Image *o; + int frame_count = 0; + Eina_Bool animated = EINA_FALSE; + char frame_index_char[4]; + + 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(); + + if (!o->cur.file) return; + if (o->cur.frame == frame_index) return; + + if (!evas_object_image_animated_get(obj)) return; + + frame_count = evas_object_image_animated_frame_count_get(obj); + + /* limit the size of frame to FRAME_MAX */ + if ((frame_count > FRAME_MAX) || (frame_count < 0) || (frame_index > frame_count)) + return; + + if (!obj->layer->evas->engine.func->image_animated_frame_set) return; + if (!obj->layer->evas->engine.func->image_animated_frame_set(obj->layer->evas->engine.data.output, o->engine_data, frame_index)) + return; + + o->prev.frame = o->cur.frame; + o->cur.frame = frame_index; + + o->changed = 1; + evas_object_change(obj); + +} + EAPI void evas_image_cache_flush(Evas *e) { @@ -3000,6 +3148,12 @@ evas_object_image_render_pre(Evas_Object *obj) evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); if (!o->pixel_updates) goto done; } + if (o->cur.frame != o->prev.frame) + { + evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); + if (!o->pixel_updates) goto done; + } + } /* if it changed geometry - and obviously not visibility or color */ /* calculate differences since we have a constant color fill */ diff --git a/legacy/evas/src/lib/engines/common/evas_image.h b/legacy/evas/src/lib/engines/common/evas_image.h index 6d5c620079..300697c487 100644 --- a/legacy/evas/src/lib/engines/common/evas_image.h +++ b/legacy/evas/src/lib/engines/common/evas_image.h @@ -54,6 +54,7 @@ EAPI void EAPI int evas_common_load_rgba_image_module_from_file (Image_Entry *im); EAPI int evas_common_load_rgba_image_data_from_file (Image_Entry *im); +EAPI double evas_common_load_rgba_image_frame_duration_from_file(Image_Entry *im, int start_frame, int frame_num); void _evas_common_rgba_image_post_surface(Image_Entry *ie); diff --git a/legacy/evas/src/lib/engines/common/evas_image_load.c b/legacy/evas/src/lib/engines/common/evas_image_load.c index cb01308501..c7eff3fb2e 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_load.c +++ b/legacy/evas/src/lib/engines/common/evas_image_load.c @@ -309,7 +309,7 @@ evas_common_load_rgba_image_data_from_file(Image_Entry *ie) Evas_Image_Load_Func *evas_image_load_func = NULL; int ret = EVAS_LOAD_ERROR_NONE; - if (ie->flags.loaded) return EVAS_LOAD_ERROR_GENERIC; + if ((ie->flags.loaded) && (!ie->flags.animated)) return EVAS_LOAD_ERROR_GENERIC; #ifdef EVAS_CSERVE if (ie->data1) @@ -346,6 +346,20 @@ evas_common_load_rgba_image_data_from_file(Image_Entry *ie) return EVAS_LOAD_ERROR_NONE; } +EAPI double +evas_common_load_rgba_image_frame_duration_from_file(Image_Entry *ie, const int start, const int frame_num) +{ + Evas_Image_Load_Func *evas_image_load_func = NULL; + + if (!ie->info.module) return -1; + + evas_image_load_func = ie->info.loader; + evas_module_use((Evas_Module*) ie->info.module); + if (evas_image_load_func->frame_duration) + return evas_image_load_func->frame_duration(ie, ie->file, start, frame_num); + return -1; +} + EAPI Eina_Bool evas_common_extension_can_load_get(const char *file) { diff --git a/legacy/evas/src/lib/engines/common/evas_image_main.c b/legacy/evas/src/lib/engines/common/evas_image_main.c index 42fb0d930e..122bd869f6 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_main.c +++ b/legacy/evas/src/lib/engines/common/evas_image_main.c @@ -188,6 +188,20 @@ _evas_common_rgba_image_delete(Image_Entry *ie) } } */ + if (ie->frames) + { + Eina_List *l; + Image_Entry_Frame *frame; + EINA_LIST_FOREACH(ie->frames, l, frame) + { + if (frame) + { + if (frame->data) free(frame->data); + if (frame->info) free(frame->info); + free (frame); + } + } + } free(im); } @@ -351,6 +365,7 @@ _evas_common_rgba_image_surface_delete(Image_Entry *ie) else if (ie->data1) evas_cserve_image_free(ie); #endif + im->image.data = NULL; ie->allocated.w = 0; ie->allocated.h = 0; diff --git a/legacy/evas/src/lib/engines/common/evas_image_scalecache.c b/legacy/evas/src/lib/engines/common/evas_image_scalecache.c index 9b846a3aa5..24a4f2d04a 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_scalecache.c +++ b/legacy/evas/src/lib/engines/common/evas_image_scalecache.c @@ -728,7 +728,7 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst, didpop = 1; } } - if (sci->im) + if (sci->im && !ie->flags.animated) { if (!didpop) { diff --git a/legacy/evas/src/lib/include/evas_common.h b/legacy/evas/src/lib/include/evas_common.h index ddaefb8646..796efac93d 100644 --- a/legacy/evas/src/lib/include/evas_common.h +++ b/legacy/evas/src/lib/include/evas_common.h @@ -357,6 +357,7 @@ typedef unsigned char DATA8; typedef struct _Image_Entry Image_Entry; typedef struct _Image_Entry_Flags Image_Entry_Flags; +typedef struct _Image_Entry_Frame Image_Entry_Frame; typedef struct _Image_Timestamp Image_Timestamp; typedef struct _Engine_Image_Entry Engine_Image_Entry; typedef struct _Evas_Cache_Target Evas_Cache_Target; @@ -511,6 +512,15 @@ struct _Image_Entry_Flags Eina_Bool delete_me : 1; Eina_Bool pending : 1; #endif + Eina_Bool animated : 1; +}; + +struct _Image_Entry_Frame +{ + int index; + DATA32 *data; /* frame decoding data */ + void *info; /* special image type info */ + Eina_Bool loaded : 1; }; struct _Evas_Cache_Target @@ -593,6 +603,13 @@ struct _Image_Entry int connect_num; int channel; int load_error; + + /* for animation feature */ + int frame_count; + Evas_Image_Animated_Loop_Hint loop_hint; + int loop_count; + int cur_frame; + Eina_List *frames; }; struct _Engine_Image_Entry diff --git a/legacy/evas/src/lib/include/evas_private.h b/legacy/evas/src/lib/include/evas_private.h index 2db318d331..4a628a7179 100644 --- a/legacy/evas/src/lib/include/evas_private.h +++ b/legacy/evas/src/lib/include/evas_private.h @@ -818,6 +818,14 @@ struct _Evas_Func void *(*gl_api_get) (void *data); int (*image_load_error_get) (void *data, void *image); int (*font_run_end_get) (void *data, Evas_Font_Set *font, Evas_Font_Instance **script_fi, Evas_Font_Instance **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len); + + /* animated feature */ + Eina_Bool (*image_animated_get) (void *data, void *image); + int (*image_animated_frame_count_get) (void *data, void *image); + Evas_Image_Animated_Loop_Hint (*image_animated_loop_type_get) (void *data, void *image); + int (*image_animated_loop_count_get) (void *data, void *image); + double (*image_animated_frame_duration_get) (void *data, void *image, int start_frame, int frame_num); + Eina_Bool (*image_animated_frame_set) (void *data, void *image, int frame_index); }; struct _Evas_Image_Load_Func @@ -825,6 +833,7 @@ struct _Evas_Image_Load_Func Eina_Bool threadable; Eina_Bool (*file_head) (Image_Entry *ie, const char *file, const char *key, int *error); Eina_Bool (*file_data) (Image_Entry *ie, const char *file, const char *key, int *error); + double (*frame_duration) (Image_Entry *ie, const char *file, const int start, const int frame_num); }; struct _Evas_Image_Save_Func diff --git a/legacy/evas/src/modules/engines/gl_x11/evas_engine.c b/legacy/evas/src/modules/engines/gl_x11/evas_engine.c index 640463693d..e92a91be84 100644 --- a/legacy/evas/src/modules/engines/gl_x11/evas_engine.c +++ b/legacy/evas/src/modules/engines/gl_x11/evas_engine.c @@ -2902,6 +2902,74 @@ eng_image_load_error_get(void *data __UNUSED__, void *image) return im->im->cache_entry.load_error; } +static Eina_Bool +eng_image_animated_get(void *data __UNUSED__, void *image) +{ + Image_Entry *im; + + if (!image) return EINA_FALSE; + im = image; + return im->flags.animated; +} + +static int +eng_image_animated_frame_count_get(void *data __UNUSED__, void *image) +{ + Image_Entry *im; + + if (!image) return -1; + im = image; + if (!im->flags.animated) return -1; + return im->frame_count; +} + +static Evas_Image_Animated_Loop_Hint +eng_image_animated_loop_type_get(void *data __UNUSED__, void *image) +{ + Image_Entry *im; + + if (!image) return EVAS_IMAGE_ANIMATED_HINT_NONE; + im = image; + if (!im->flags.animated) return EVAS_IMAGE_ANIMATED_HINT_NONE; + return im->loop_hint; +} + +static int +eng_image_animated_loop_count_get(void *data __UNUSED__, void *image) +{ + Image_Entry *im; + + if (!image) return -1; + im = image; + if (!im->flags.animated) return -1; + return im->loop_count; +} + +static double +eng_image_animated_frame_duration_get(void *data __UNUSED__, void *image, int start_frame, int frame_num) +{ + Image_Entry *im; + + if (!image) return -1; + im = image; + if (!im->flags.animated) return -1; + return evas_common_load_rgba_image_frame_duration_from_file(im, start_frame, frame_num); +} + +static Eina_Bool +eng_image_animated_frame_set(void *data __UNUSED__, void *image, int frame_index) +{ + Image_Entry *im; + + if (!image) return EINA_FALSE; + im = image; + if (!im->flags.animated) return EINA_FALSE; + if (im->cur_frame == frame_index) return EINA_FALSE; + + im->cur_frame = frame_index; + return EINA_TRUE; +} + static int module_open(Evas_Module *em) { @@ -3010,6 +3078,14 @@ module_open(Evas_Module *em) ORD(image_load_error_get); + /* now advertise out own api */ + ORD(image_animated_get); + ORD(image_animated_frame_count_get); + ORD(image_animated_loop_type_get); + ORD(image_animated_loop_count_get); + ORD(image_animated_frame_duration_get); + ORD(image_animated_frame_set); + /* now advertise out own api */ em->functions = (void *)(&func); return 1; diff --git a/legacy/evas/src/modules/engines/software_generic/evas_engine.c b/legacy/evas/src/modules/engines/software_generic/evas_engine.c index b0a08ef43f..966366569a 100644 --- a/legacy/evas/src/modules/engines/software_generic/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_generic/evas_engine.c @@ -653,6 +653,73 @@ eng_image_scale_hint_get(void *data __UNUSED__, void *image) return im->scale_hint; } +static Eina_Bool +eng_image_animated_get(void *data __UNUSED__, void *image) +{ + Image_Entry *im; + + if (!image) return EINA_FALSE; + im = image; + return im->flags.animated; +} + +static int +eng_image_animated_frame_count_get(void *data __UNUSED__, void *image) +{ + Image_Entry *im; + + if (!image) return -1; + im = image; + if (!im->flags.animated) return -1; + return im->frame_count; +} + +static Evas_Image_Animated_Loop_Hint +eng_image_animated_loop_type_get(void *data __UNUSED__, void *image) +{ + Image_Entry *im; + + if (!image) return EVAS_IMAGE_ANIMATED_HINT_NONE; + im = image; + if (!im->flags.animated) return EVAS_IMAGE_ANIMATED_HINT_NONE; + return im->loop_hint; +} + +static int +eng_image_animated_loop_count_get(void *data __UNUSED__, void *image) +{ + Image_Entry *im; + + if (!image) return -1; + im = image; + if (!im->flags.animated) return -1; + return im->loop_count; +} + +static double +eng_image_animated_frame_duration_get(void *data __UNUSED__, void *image, int start_frame, int frame_num) +{ + Image_Entry *im; + + if (!image) return -1; + im = image; + if (!im->flags.animated) return -1; + return evas_common_load_rgba_image_frame_duration_from_file(im, start_frame, frame_num); +} + +static Eina_Bool +eng_image_animated_frame_set(void *data __UNUSED__, void *image, int frame_index) +{ + Image_Entry *im; + + if (!image) return EINA_FALSE; + im = image; + if (!im->flags.animated) return EINA_FALSE; + if (im->cur_frame == frame_index) return EINA_FALSE; + im->cur_frame = frame_index; + return EINA_TRUE; +} + static void eng_image_cache_flush(void *data __UNUSED__) { @@ -1099,7 +1166,13 @@ static Evas_Func func = NULL, // FIXME: need software mesa for gl rendering <- gl_native_surface_get NULL, // FIXME: need software mesa for gl rendering <- gl_api_get eng_image_load_error_get, - eng_font_run_font_end_get + eng_font_run_font_end_get, + eng_image_animated_get, + eng_image_animated_frame_count_get, + eng_image_animated_loop_type_get, + eng_image_animated_loop_count_get, + eng_image_animated_frame_duration_get, + eng_image_animated_frame_set /* FUTURE software generic calls go here */ }; diff --git a/legacy/evas/src/modules/loaders/bmp/evas_image_load_bmp.c b/legacy/evas/src/modules/loaders/bmp/evas_image_load_bmp.c index f2ee9bf16a..a391ef89c2 100644 --- a/legacy/evas/src/modules/loaders/bmp/evas_image_load_bmp.c +++ b/legacy/evas/src/modules/loaders/bmp/evas_image_load_bmp.c @@ -18,7 +18,8 @@ static Evas_Image_Load_Func evas_image_load_bmp_func = { EINA_TRUE, evas_image_load_file_head_bmp, - evas_image_load_file_data_bmp + evas_image_load_file_data_bmp, + NULL }; static int diff --git a/legacy/evas/src/modules/loaders/edb/evas_image_load_edb.c b/legacy/evas/src/modules/loaders/edb/evas_image_load_edb.c index 239a072dba..94b121e536 100644 --- a/legacy/evas/src/modules/loaders/edb/evas_image_load_edb.c +++ b/legacy/evas/src/modules/loaders/edb/evas_image_load_edb.c @@ -15,7 +15,8 @@ static Evas_Image_Load_Func evas_image_load_edb_func = { EINA_TRUE, evas_image_load_file_head_edb, - evas_image_load_file_data_edb + evas_image_load_file_data_edb, + NULL }; static Eina_Bool diff --git a/legacy/evas/src/modules/loaders/eet/evas_image_load_eet.c b/legacy/evas/src/modules/loaders/eet/evas_image_load_eet.c index c6d2783a10..a187b9eacb 100644 --- a/legacy/evas/src/modules/loaders/eet/evas_image_load_eet.c +++ b/legacy/evas/src/modules/loaders/eet/evas_image_load_eet.c @@ -15,7 +15,8 @@ Evas_Image_Load_Func evas_image_load_eet_func = { EINA_TRUE, evas_image_load_file_head_eet, - evas_image_load_file_data_eet + evas_image_load_file_data_eet, + NULL }; diff --git a/legacy/evas/src/modules/loaders/generic/evas_image_load_generic.c b/legacy/evas/src/modules/loaders/generic/evas_image_load_generic.c index 83b10e0c8a..1a01714191 100644 --- a/legacy/evas/src/modules/loaders/generic/evas_image_load_generic.c +++ b/legacy/evas/src/modules/loaders/generic/evas_image_load_generic.c @@ -23,7 +23,8 @@ Evas_Image_Load_Func evas_image_load_generic_func = { EINA_TRUE, evas_image_load_file_head_generic, - evas_image_load_file_data_generic + evas_image_load_file_data_generic, + NULL }; static Eina_Bool diff --git a/legacy/evas/src/modules/loaders/gif/evas_image_load_gif.c b/legacy/evas/src/modules/loaders/gif/evas_image_load_gif.c index 2b67c64a18..8b36e30d30 100644 --- a/legacy/evas/src/modules/loaders/gif/evas_image_load_gif.c +++ b/legacy/evas/src/modules/loaders/gif/evas_image_load_gif.c @@ -8,15 +8,469 @@ #include +typedef struct _Gif_Frame Gif_Frame; + +typedef enum _Frame_Load_Type +{ + LOAD_FRAME_NONE = 0, + LOAD_FRAME_INFO = 1, + LOAD_FRAME_DATA = 2, + LOAD_FRAME_DATA_INFO = 3 +} Frame_Load_Type; + +struct _Gif_Frame +{ + struct { + /* Image descriptor */ + int x; + int y; + int w; + int h; + int interlace; + } image_des; + + struct { + /* Graphic Control*/ + int disposal; + int transparent; + int delay; + int input; + } frame_info; +}; + +static Eina_Bool evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error); + static Eina_Bool evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4); static Eina_Bool evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4); +static double evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, int start_frame, int frame_num) ; +static Eina_Bool evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error); static Evas_Image_Load_Func evas_image_load_gif_func = { EINA_TRUE, evas_image_load_file_head_gif, - evas_image_load_file_data_gif + evas_image_load_file_data_gif, + evas_image_load_frame_duration_gif }; +#define byte2_to_int(a,b) (((b)<<8)|(a)) + +#define FRAME_MAX 1024 + +/* find specific frame in image entry */ +static Eina_Bool +_find_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame) +{ + Eina_List *l; + Image_Entry_Frame *hit_frame = NULL; + + if (!ie) return EINA_FALSE; + if (!ie->frames) return EINA_FALSE; + + EINA_LIST_FOREACH(ie->frames, l, hit_frame) + { + if (hit_frame->index == frame_index) + { + *frame = hit_frame; + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +static Eina_Bool +_find_close_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame) +{ + int i; + Eina_Bool hit = EINA_FALSE; + i = frame_index -1; + + if (!ie) return EINA_FALSE; + if (!ie->frames) return EINA_FALSE; + + for (; i > 0; i--) + { + hit = _find_frame(ie, i, frame); + if (hit) + return EINA_TRUE; + } + return EINA_FALSE; +} + +static Eina_Bool +_evas_image_skip_frame(GifFileType *gif, int frame) +{ + int remain_frame = 0; + GifRecordType rec; + + if (!gif) return EINA_FALSE; + if (frame == 0) return EINA_TRUE; /* no need to skip */ + if (frame < 0 || frame > FRAME_MAX) return EINA_FALSE; + + remain_frame = frame; + + do + { + if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE; + + if (rec == EXTENSION_RECORD_TYPE) + { + int ext_code; + GifByteType *ext; + + ext = NULL; + DGifGetExtension(gif, &ext_code, &ext); + while (ext) + { /*skip extention */ + ext = NULL; + DGifGetExtensionNext(gif, &ext); + } + } + + if (rec == IMAGE_DESC_RECORD_TYPE) + { + int img_code; + GifByteType *img; + + if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE; + + remain_frame --; + /* we have to count frame, so use DGifGetCode and skip decoding */ + if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) return EINA_FALSE; + + while (img) + { + img = NULL; + DGifGetCodeNext(gif, &img); + } + if (remain_frame < 1) return EINA_TRUE; + } + if (rec == TERMINATE_RECORD_TYPE) return EINA_FALSE; /* end of file */ + + } while ((rec != TERMINATE_RECORD_TYPE) && (remain_frame > 0)); + return EINA_FALSE; +} + +static Eina_Bool +_evas_image_load_frame_graphic_info(Image_Entry_Frame *frame, GifByteType *ext) +{ + Gif_Frame *gif_frame = NULL; + if ((!frame) || (!ext)) return EINA_FALSE; + + gif_frame = (Gif_Frame *) frame->info; + + /* transparent */ + if ((ext[1] & 0x1) != 0) + gif_frame->frame_info.transparent = ext[4]; + else + gif_frame->frame_info.transparent = -1; + + gif_frame->frame_info.input = (ext[1] >>1) & 0x1; + gif_frame->frame_info.disposal = (ext[1] >>2) & 0x7; + gif_frame->frame_info.delay = byte2_to_int(ext[2], ext[3]); + return EINA_TRUE; +} + +static Eina_Bool +_evas_image_load_frame_image_des_info(GifFileType *gif, Image_Entry_Frame *frame) +{ + Gif_Frame *gif_frame = NULL; + if ((!gif) || (!frame)) return EINA_FALSE; + + gif_frame = (Gif_Frame *) frame->info; + gif_frame->image_des.x = gif->Image.Left; + gif_frame->image_des.y = gif->Image.Top; + gif_frame->image_des.w = gif->Image.Width; + gif_frame->image_des.h = gif->Image.Height; + gif_frame->image_des.interlace = gif->Image.Interlace; + return EINA_TRUE; +} + +static Eina_Bool +_evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, int *error) +{ + int w; + int h; + int x; + int y; + int i,j; + int bg; + int r; + int g; + int b; + int alpha; + double per; + double per_inc; + ColorMapObject *cmap; + GifRowType *rows; + int intoffset[] = { 0, 4, 2, 1 }; + int intjump[] = { 8, 8, 4, 2 }; + size_t siz; + int cache_w; + int cache_h; + int cur_h; + int cur_w; + DATA32 *ptr; + Gif_Frame *gif_frame = NULL; + + if ((!gif) || (!frame)) return EINA_FALSE; + + gif_frame = (Gif_Frame *) frame->info; + w = gif->Image.Width; + h = gif->Image.Height; + x = gif->Image.Left; + y = gif->Image.Top; + cache_w = ie->w; + cache_h = ie->h; + + rows = malloc(h * sizeof(GifRowType *)); + if (!rows) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + for (i = 0; i < h; i++) + { + rows[i] = NULL; + } + for (i = 0; i < h; i++) + { + rows[i] = malloc(w * sizeof(GifPixelType)); + if (!rows[i]) + { + for (i = 0; i < h; i++) + { + if (rows[i]) + { + free(rows[i]); + } + } + free(rows); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + } + if (gif->Image.Interlace) + { + for (i = 0; i < 4; i++) + { + for (j = intoffset[i]; j < h; j += intjump[i]) + { + DGifGetLine(gif, rows[j], w); + } + } + } + else + { + for (i = 0; i < h; i++) + { + if (DGifGetLine(gif, rows[i], w) != GIF_OK) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + goto error; + } + } + } + alpha = gif_frame->frame_info.transparent; + siz = cache_w *cache_h * sizeof(DATA32); + frame->data = malloc(siz); + if (!frame->data) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + goto error; + } + ptr = frame->data; + bg = gif->SBackGroundColor; + cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap); + + per_inc = 100.0 / (((double)w) * h); + cur_h = h; + cur_w = w; + if (cur_h > cache_h) cur_h = cache_h; + if (cur_w > cache_w) cur_w = cache_w; + + if (frame->index > 1) + { + /* get previous frame only frame index is bigger than 1 */ + DATA32 *ptr_src; + Image_Entry_Frame *new_frame = NULL; + int cur_frame = frame->index; + + if (!_find_close_frame(ie, cur_frame, &new_frame)) + { + if (!evas_image_load_specific_frame(ie, ie->file, cur_frame-1, error)) + { + *error = EVAS_LOAD_ERROR_CORRUPT_FILE; + goto error; + } + } + else + { + ptr_src = new_frame->data; + memcpy(ptr, ptr_src, siz); + } + + /* composite frames */ + ptr = ptr + cache_w * y; + + for (i = 0; i < cur_h; i++) + { + ptr = ptr + x; + for (j = 0; j < cur_w; j++) + { + if (rows[i][j] == alpha) + { + ptr++ ; + } + else + { + r = cmap->Colors[rows[i][j]].Red; + g = cmap->Colors[rows[i][j]].Green; + b = cmap->Colors[rows[i][j]].Blue; + *ptr++ = ARGB_JOIN(0xff, r, g, b); + } + per += per_inc; + } + ptr = ptr + (cache_w - (x + cur_w)); + } + } + else + { + ptr = ptr + cache_w * y; + + for (i = 0; i < cur_h; i++) + { + ptr = ptr + x; + for (j = 0; j < cur_w; j++) + { + r = cmap->Colors[rows[i][j]].Red; + g = cmap->Colors[rows[i][j]].Green; + b = cmap->Colors[rows[i][j]].Blue; + *ptr++ = ARGB_JOIN(0xff, r, g, b); + + per += per_inc; + } + ptr = ptr + (cache_w - (x + cur_w)); + } + } + + for (i = 0; i < h; i++) + { + if (rows[i]) free(rows[i]); + } + if (rows) free(rows); + frame->loaded = EINA_TRUE; + return EINA_TRUE; +error: + for (i = 0; i < h; i++) + { + if (rows[i]) free(rows[i]); + } + if (rows) free(rows); + return EINA_FALSE; +} + +static Eina_Bool +_evas_image_load_frame(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, Frame_Load_Type type, int *error) +{ + GifRecordType rec; + int gra_res = 0, img_res = 0; + Eina_Bool res = EINA_FALSE; + Gif_Frame *gif_frame = NULL; + + if ((!gif) || (!frame)) return EINA_FALSE; + gif_frame = (Gif_Frame *) frame->info; + + if (LOAD_FRAME_NONE > type || LOAD_FRAME_DATA_INFO < type) return EINA_FALSE; + + do + { + if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE; + if (rec == IMAGE_DESC_RECORD_TYPE) + { + img_res++; + break; + } + else if (rec = EXTENSION_RECORD_TYPE) + { + int ext_code; + GifByteType *ext; + + ext = NULL; + DGifGetExtension(gif, &ext_code, &ext); + while (ext) + { + if (ext_code == 0xf9) /* Graphic Control Extension */ + { + gra_res++; + /* fill frame info */ + if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO)) + _evas_image_load_frame_graphic_info(frame,ext); + } + ext = NULL; + DGifGetExtensionNext(gif, &ext); + } + } + } while ((rec != TERMINATE_RECORD_TYPE) && (img_res == 0)); + if (img_res != 1) return EINA_FALSE; + if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE; + if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO)) + _evas_image_load_frame_image_des_info(gif, frame); + + if ((type == LOAD_FRAME_DATA) || (type == LOAD_FRAME_DATA_INFO)) + { + res = _evas_image_load_frame_image_data(ie, gif,frame, error); + if (!res) return EINA_FALSE; + } + return EINA_TRUE; +} + + +/* set frame data to cache entry's data */ +static Eina_Bool +evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error) +{ + int w; + int h; + int dst_x; + int dst_y; + DATA32 *dst; + DATA32 *src; + int cache_w, cache_h; + size_t siz; + Gif_Frame *gif_frame = NULL; + + gif_frame = (Gif_Frame *) frame->info; + cache_w = ie->w; + cache_h = ie->h; + w = gif_frame->image_des.w; + h = gif_frame->image_des.h; + dst_x = gif_frame->image_des.x; + dst_y = gif_frame->image_des.y; + + src = frame->data; + + if (!evas_cache_image_pixels(ie)) + { + evas_cache_image_surface_alloc(ie, cache_w, cache_h); + } + + if (!evas_cache_image_pixels(ie)) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + + /* only copy real frame part */ + siz = cache_w * cache_h * sizeof(DATA32); + dst = evas_cache_image_pixels(ie); + + memcpy(dst, src, siz); + + evas_common_image_premul(ie); + + *error = EVAS_LOAD_ERROR_NONE; + return EINA_TRUE; +} static Eina_Bool evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error) @@ -24,12 +478,11 @@ evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key int fd; GifFileType *gif; GifRecordType rec; - int done; int w; int h; int alpha; + int loop_count = -1; - done = 0; w = 0; h = 0; alpha = -1; @@ -41,45 +494,71 @@ evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key #endif if (fd < 0) { - *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; - return EINA_FALSE; + *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; + return EINA_FALSE; } gif = DGifOpenFileHandle(fd); if (!gif) { - close(fd); - *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; - return EINA_FALSE; + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; } + /* check logical screen size */ + w = gif->SWidth; + h = gif->SHeight; + + if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) || + IMG_TOO_BIG(w, h)) + { + DGifCloseFile(gif); + if (IMG_TOO_BIG(w, h)) + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + else + *error = EVAS_LOAD_ERROR_GENERIC; + return EINA_FALSE; + } + ie->w = w; + ie->h = h; + do { if (DGifGetRecordType(gif, &rec) == GIF_ERROR) { /* PrintGifError(); */ - rec = TERMINATE_RECORD_TYPE; + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; } - if ((rec == IMAGE_DESC_RECORD_TYPE) && (!done)) + + /* image descript info */ + if (rec == IMAGE_DESC_RECORD_TYPE) { + int img_code; + GifByteType *img; + if (DGifGetImageDesc(gif) == GIF_ERROR) { /* PrintGifError(); */ - rec = TERMINATE_RECORD_TYPE; + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + /* we have to count frame, so use DGifGetCode and skip decoding */ + if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) + { + /* PrintGifError(); */ + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + while (img) + { + img = NULL; + DGifGetCodeNext(gif, &img); } - w = gif->Image.Width; - h = gif->Image.Height; - if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) || - IMG_TOO_BIG(w, h)) - { - DGifCloseFile(gif); - if (IMG_TOO_BIG(w, h)) - *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; - else - *error = EVAS_LOAD_ERROR_GENERIC; - return EINA_FALSE; - } - done = 1; } else if (rec == EXTENSION_RECORD_TYPE) { @@ -90,10 +569,26 @@ evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key DGifGetExtension(gif, &ext_code, &ext); while (ext) { - if ((ext_code == 0xf9) && (ext[1] & 1) && (alpha < 0)) + if (ext_code == 0xf9) /* Graphic Control Extension */ { - alpha = (int)ext[4]; + if ((ext[1] & 1) && (alpha < 0)) alpha = (int)ext[4]; } + else if (ext_code == 0xff) /* application extension */ + { + if (!strncmp ((char*)(&ext[1]), "NETSCAPE2.0", 11) || + !strncmp ((char*)(&ext[1]), "ANIMEXTS1.0", 11)) + { + ext=NULL; + DGifGetExtensionNext(gif, &ext); + + if (ext[1] == 0x01) + { + loop_count = ext[2] + (ext[3] << 8); + if (loop_count > 0) loop_count++; + } + } + } + ext = NULL; DGifGetExtensionNext(gif, &ext); } @@ -101,8 +596,15 @@ evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key } while (rec != TERMINATE_RECORD_TYPE); if (alpha >= 0) ie->flags.alpha = 1; - ie->w = w; - ie->h = h; + + if (gif->ImageCount > 1) + { + ie->flags.animated = 1; + ie->loop_count = loop_count; + ie->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP; + ie->frame_count = gif->ImageCount; + ie->frames = NULL; + } DGifCloseFile(gif); *error = EVAS_LOAD_ERROR_NONE; @@ -110,39 +612,12 @@ evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key } static Eina_Bool -evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error) +evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error) { - int intoffset[] = { 0, 4, 2, 1 }; - int intjump[] = { 8, 8, 4, 2 }; - double per; - double per_inc; - int fd; - GifFileType *gif; - GifRecordType rec; - GifRowType *rows; - ColorMapObject *cmap; - DATA32 *ptr; - int done; - int last_y; - int last_per; - int w; - int h; - int alpha; - int i; - int j; - int bg; - int r; - int g; - int b; - - rows = NULL; - per = 0.0; - done = 0; - last_y = 0; - last_per = 0; - w = 0; - h = 0; - alpha = -1; + int fd; + GifFileType *gif; + Image_Entry_Frame *frame = NULL; + Gif_Frame *gif_frame = NULL; #ifndef __EMX__ fd = open(file, O_RDONLY); @@ -151,79 +626,206 @@ evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key #endif if (fd < 0) { - *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; - return EINA_FALSE; + *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; + return EINA_FALSE; } gif = DGifOpenFileHandle(fd); if (!gif) { - close(fd); - *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; - return EINA_FALSE; + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; } + if (!_evas_image_skip_frame(gif, frame_index-1)) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + + frame = malloc(sizeof (Image_Entry_Frame)); + if (!frame) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + + gif_frame = malloc(sizeof (Gif_Frame)); + if (!gif_frame) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + frame->info = gif_frame; + frame->index = frame_index; + if (!_evas_image_load_frame(ie,gif, frame, LOAD_FRAME_DATA_INFO,error)) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + + ie->frames = eina_list_append(ie->frames, frame); + DGifCloseFile(gif); + return EINA_TRUE; +} + +static Eina_Bool +evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error) +{ + int cur_frame_index; + Image_Entry_Frame *frame = NULL; + Eina_Bool hit; + + if(!ie->flags.animated) + cur_frame_index = 1; + else + cur_frame_index = ie->cur_frame; + + if ((ie->flags.animated) && + ((cur_frame_index <0) || (cur_frame_index > FRAME_MAX) || (cur_frame_index > ie->frame_count))) + { + *error = EVAS_LOAD_ERROR_GENERIC; + return EINA_FALSE; + } + + /* first time frame is set to be 0. so default is 1 */ + if (cur_frame_index == 0) cur_frame_index++; + + /* Check current frame exists in hash table */ + hit = _find_frame(ie, cur_frame_index, &frame); + + /* if current frame exist in has table, check load flag */ + if (hit) + { + if (frame->loaded) + evas_image_load_file_data_gif_internal(ie,frame,error); + else + { + int fd; + GifFileType *gif; + +#ifndef __EMX__ + fd = open(file, O_RDONLY); +#else + fd = open(file, O_RDONLY | O_BINARY); +#endif + if (fd < 0) + { + *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; + return EINA_FALSE; + } + + gif = DGifOpenFileHandle(fd); + if (!gif) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + _evas_image_skip_frame(gif, cur_frame_index-1); + if (!_evas_image_load_frame(ie, gif, frame, LOAD_FRAME_DATA,error)) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + if (!evas_image_load_file_data_gif_internal(ie, frame, error)) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_NONE; + return EINA_TRUE; + } + } + /* current frame does is not exist */ + else + { + if (!evas_image_load_specific_frame(ie, file, cur_frame_index, error)) + { + return EINA_FALSE; + } + hit = EINA_FALSE; + frame = NULL; + hit = _find_frame(ie, cur_frame_index, &frame); + if (!hit) return EINA_FALSE; + if (!evas_image_load_file_data_gif_internal(ie, frame, error)) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + return EINA_TRUE; + } + return EINA_FALSE; +} + +static double +evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int start_frame, const int frame_num) +{ + int fd; + GifFileType *gif; + GifRecordType rec; + int done; + int current_frame = 1; + int remain_frames = frame_num; + double duration = 0; + int frame_count = 0; + + frame_count = ie->frame_count; + + if (!ie->flags.animated) return -1; + if ((start_frame + frame_num) > frame_count) return -1; + if (frame_num < 0) return -1; + + done = 0; + +#ifndef __EMX__ + fd = open(file, O_RDONLY); +#else + fd = open(file, O_RDONLY | O_BINARY); +#endif + if (fd < 0) return -1; + + gif = DGifOpenFileHandle(fd); + if (!gif) + { + if (fd) close(fd); + return -1; + } + do { if (DGifGetRecordType(gif, &rec) == GIF_ERROR) { - /* PrintGifError(); */ rec = TERMINATE_RECORD_TYPE; } - if ((rec == IMAGE_DESC_RECORD_TYPE) && (!done)) + if (rec == IMAGE_DESC_RECORD_TYPE) { + int img_code; + GifByteType *img; + if (DGifGetImageDesc(gif) == GIF_ERROR) { /* PrintGifError(); */ rec = TERMINATE_RECORD_TYPE; } - w = gif->Image.Width; - h = gif->Image.Height; - rows = malloc(h * sizeof(GifRowType *)); - if (!rows) + current_frame++; + /* we have to count frame, so use DGifGetCode and skip decoding */ + if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) { - DGifCloseFile(gif); - return 0; + rec = TERMINATE_RECORD_TYPE; } - for (i = 0; i < h; i++) + while (img) { - rows[i] = NULL; + img = NULL; + DGifGetExtensionNext(gif, &img); } - for (i = 0; i < h; i++) - { - rows[i] = malloc(w * sizeof(GifPixelType)); - if (!rows[i]) - { - DGifCloseFile(gif); - for (i = 0; i < h; i++) - { - if (rows[i]) - { - free(rows[i]); - } - } - free(rows); - *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; - return EINA_FALSE; - } - } - if (gif->Image.Interlace) - { - for (i = 0; i < 4; i++) - { - for (j = intoffset[i]; j < h; j += intjump[i]) - { - DGifGetLine(gif, rows[j], w); - } - } - } - else - { - for (i = 0; i < h; i++) - { - DGifGetLine(gif, rows[i], w); - } - } - done = 1; } else if (rec == EXTENSION_RECORD_TYPE) { @@ -234,78 +836,28 @@ evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key DGifGetExtension(gif, &ext_code, &ext); while (ext) { - if ((ext_code == 0xf9) && (ext[1] & 1) && (alpha < 0)) + if (ext_code == 0xf9) /* Graphic Control Extension */ { - alpha = (int)ext[4]; + if ((current_frame >= start_frame) && (current_frame <= frame_count)) + { + int frame_duration = 0; + if (remain_frames < 0) break; + frame_duration = byte2_to_int (ext[2], ext[3]); + if (frame_duration == 0) + duration += 0.1; + else + duration += (double)frame_duration/100; + remain_frames --; + } } ext = NULL; DGifGetExtensionNext(gif, &ext); } - } - } while (rec != TERMINATE_RECORD_TYPE); - - if (alpha >= 0) ie->flags.alpha = 1; - evas_cache_image_surface_alloc(ie, w, h); - if (!evas_cache_image_pixels(ie)) - { - DGifCloseFile(gif); - for (i = 0; i < h; i++) - { - free(rows[i]); - } - free(rows); - *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; - return EINA_FALSE; - } - - bg = gif->SBackGroundColor; - cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap); - if (!cmap) - { - DGifCloseFile(gif); - for (i = 0; i < h; i++) - { - free(rows[i]); - } - free(rows); - *error = EVAS_LOAD_ERROR_CORRUPT_FILE; - return EINA_FALSE; - } - - ptr = evas_cache_image_pixels(ie); - per_inc = 100.0 / (((double)w) * h); - - for (i = 0; i < h; i++) - { - for (j = 0; j < w; j++) - { - if (rows[i][j] == alpha) - { - r = cmap->Colors[bg].Red; - g = cmap->Colors[bg].Green; - b = cmap->Colors[bg].Blue; - *ptr++ = 0x00ffffff & RGB_JOIN(r, g, b); - } - else - { - r = cmap->Colors[rows[i][j]].Red; - g = cmap->Colors[rows[i][j]].Green; - b = cmap->Colors[rows[i][j]].Blue; - *ptr++ = ARGB_JOIN(0xff, r, g, b); - } - per += per_inc; } - } - evas_common_image_premul(ie); - DGifCloseFile(gif); - for (i = 0; i < h; i++) - { - free(rows[i]); - } - free(rows); + } while (rec != TERMINATE_RECORD_TYPE); - *error = EVAS_LOAD_ERROR_NONE; - return EINA_TRUE; + DGifCloseFile(gif); + return duration; } static int diff --git a/legacy/evas/src/modules/loaders/ico/evas_image_load_ico.c b/legacy/evas/src/modules/loaders/ico/evas_image_load_ico.c index 1885c1515b..17a7f7e08e 100644 --- a/legacy/evas/src/modules/loaders/ico/evas_image_load_ico.c +++ b/legacy/evas/src/modules/loaders/ico/evas_image_load_ico.c @@ -18,7 +18,8 @@ static Evas_Image_Load_Func evas_image_load_ico_func = { EINA_TRUE, evas_image_load_file_head_ico, - evas_image_load_file_data_ico + evas_image_load_file_data_ico, + NULL }; static int diff --git a/legacy/evas/src/modules/loaders/jpeg/evas_image_load_jpeg.c b/legacy/evas/src/modules/loaders/jpeg/evas_image_load_jpeg.c index 404dcaebd0..9f88d1f3a5 100644 --- a/legacy/evas/src/modules/loaders/jpeg/evas_image_load_jpeg.c +++ b/legacy/evas/src/modules/loaders/jpeg/evas_image_load_jpeg.c @@ -45,7 +45,8 @@ static Evas_Image_Load_Func evas_image_load_jpeg_func = { EINA_TRUE, evas_image_load_file_head_jpeg, - evas_image_load_file_data_jpeg + evas_image_load_file_data_jpeg, + NULL }; diff --git a/legacy/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c b/legacy/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c index 001a2a02e8..9ba8f8178a 100644 --- a/legacy/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c +++ b/legacy/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c @@ -18,7 +18,8 @@ static Eina_Bool evas_image_load_file_data_pmaps(Image_Entry *ie, const char *fi Evas_Image_Load_Func evas_image_load_pmaps_func = { EINA_TRUE, evas_image_load_file_head_pmaps, - evas_image_load_file_data_pmaps + evas_image_load_file_data_pmaps, + NULL }; /* The buffer to load pmaps images */ diff --git a/legacy/evas/src/modules/loaders/png/evas_image_load_png.c b/legacy/evas/src/modules/loaders/png/evas_image_load_png.c index a2510b126b..c4a907a27a 100644 --- a/legacy/evas/src/modules/loaders/png/evas_image_load_png.c +++ b/legacy/evas/src/modules/loaders/png/evas_image_load_png.c @@ -34,7 +34,8 @@ static Evas_Image_Load_Func evas_image_load_png_func = { EINA_TRUE, evas_image_load_file_head_png, - evas_image_load_file_data_png + evas_image_load_file_data_png, + NULL }; static Eina_Bool diff --git a/legacy/evas/src/modules/loaders/psd/evas_image_load_psd.c b/legacy/evas/src/modules/loaders/psd/evas_image_load_psd.c index 2c1dfddb47..5a85e179fc 100644 --- a/legacy/evas/src/modules/loaders/psd/evas_image_load_psd.c +++ b/legacy/evas/src/modules/loaders/psd/evas_image_load_psd.c @@ -940,7 +940,8 @@ get_compressed_channels_length(PSD_Header *head, static const Evas_Image_Load_Func evas_image_load_psd_func = { EINA_TRUE, evas_image_load_file_head_psd, - evas_image_load_file_data_psd + evas_image_load_file_data_psd, + NULL }; static int diff --git a/legacy/evas/src/modules/loaders/svg/evas_image_load_svg.c b/legacy/evas/src/modules/loaders/svg/evas_image_load_svg.c index 3847481264..f1c8452e32 100644 --- a/legacy/evas/src/modules/loaders/svg/evas_image_load_svg.c +++ b/legacy/evas/src/modules/loaders/svg/evas_image_load_svg.c @@ -12,7 +12,8 @@ Evas_Image_Load_Func evas_image_load_svg_func = { EINA_FALSE, evas_image_load_file_head_svg, - evas_image_load_file_data_svg + evas_image_load_file_data_svg, + NULL }; static int rsvg_initialized = 0; diff --git a/legacy/evas/src/modules/loaders/tga/evas_image_load_tga.c b/legacy/evas/src/modules/loaders/tga/evas_image_load_tga.c index 9f66886a2a..05b277c3be 100644 --- a/legacy/evas/src/modules/loaders/tga/evas_image_load_tga.c +++ b/legacy/evas/src/modules/loaders/tga/evas_image_load_tga.c @@ -61,7 +61,8 @@ static Evas_Image_Load_Func evas_image_load_tga_func = { EINA_TRUE, evas_image_load_file_head_tga, - evas_image_load_file_data_tga + evas_image_load_file_data_tga, + NULL }; static Eina_Bool diff --git a/legacy/evas/src/modules/loaders/tiff/evas_image_load_tiff.c b/legacy/evas/src/modules/loaders/tiff/evas_image_load_tiff.c index 270afbba99..b9bea9104c 100644 --- a/legacy/evas/src/modules/loaders/tiff/evas_image_load_tiff.c +++ b/legacy/evas/src/modules/loaders/tiff/evas_image_load_tiff.c @@ -33,7 +33,8 @@ static Evas_Image_Load_Func evas_image_load_tiff_func = { EINA_TRUE, evas_image_load_file_head_tiff, - evas_image_load_file_data_tiff + evas_image_load_file_data_tiff, + NULL }; typedef struct TIFFRGBAImage_Extra TIFFRGBAImage_Extra; diff --git a/legacy/evas/src/modules/loaders/wbmp/evas_image_load_wbmp.c b/legacy/evas/src/modules/loaders/wbmp/evas_image_load_wbmp.c index 393d6da2f2..fa6fab2758 100644 --- a/legacy/evas/src/modules/loaders/wbmp/evas_image_load_wbmp.c +++ b/legacy/evas/src/modules/loaders/wbmp/evas_image_load_wbmp.c @@ -18,7 +18,8 @@ static Evas_Image_Load_Func evas_image_load_wbmp_func = { EINA_TRUE, evas_image_load_file_head_wbmp, - evas_image_load_file_data_wbmp + evas_image_load_file_data_wbmp, + NULL }; diff --git a/legacy/evas/src/modules/loaders/xpm/evas_image_load_xpm.c b/legacy/evas/src/modules/loaders/xpm/evas_image_load_xpm.c index e024f0d673..3a04f84dc1 100644 --- a/legacy/evas/src/modules/loaders/xpm/evas_image_load_xpm.c +++ b/legacy/evas/src/modules/loaders/xpm/evas_image_load_xpm.c @@ -23,7 +23,8 @@ static Evas_Image_Load_Func evas_image_load_xpm_func = { EINA_FALSE, evas_image_load_file_head_xpm, - evas_image_load_file_data_xpm + evas_image_load_file_data_xpm, + NULL }; // TODO: REWRITE THIS WITH THREAD SAFE VERSION NOT USING THIS HANDLE!!!!