evas_object_image Add Animation gif feature
authorJiyoun Park <jy0703.park@samsung.com>
Fri, 22 Jul 2011 12:38:32 +0000 (21:38 +0900)
committerJiyoun Park <jy0703.park@samsung.com>
Fri, 22 Jul 2011 12:38:32 +0000 (21:38 +0900)
I implement animation gif feature.
we will describe detail thing using document

Change-Id: I8dd67cbb36dcb06e7a4ca2a313dd2c709c1775b3

21 files changed:
src/lib/Evas.h
src/lib/cache/evas_cache_image.c
src/lib/canvas/evas_object_image.c
src/lib/engines/common/evas_image.h
src/lib/engines/common/evas_image_load.c
src/lib/engines/common/evas_image_main.c
src/lib/engines/common/evas_image_scalecache.c
src/lib/include/evas_common.h
src/lib/include/evas_private.h
src/modules/engines/gl_x11/evas_engine.c
src/modules/engines/software_generic/evas_engine.c
src/modules/loaders/bmp/evas_image_load_bmp.c
src/modules/loaders/edb/evas_image_load_edb.c
src/modules/loaders/gif/evas_image_load_gif.c
src/modules/loaders/ico/evas_image_load_ico.c
src/modules/loaders/jpeg/evas_image_load_jpeg.c
src/modules/loaders/pmaps/evas_image_load_pmaps.c
src/modules/loaders/png/evas_image_load_png.c
src/modules/loaders/tga/evas_image_load_tga.c
src/modules/loaders/tiff/evas_image_load_tiff.c
src/modules/loaders/wbmp/evas_image_load_wbmp.c

index af79db3..251a4ab 100644 (file)
@@ -697,6 +697,13 @@ typedef enum _Evas_Image_Scale_Hint
    EVAS_IMAGE_SCALE_HINT_STATIC = 2
 } Evas_Image_Scale_Hint;
 
+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,
@@ -5499,6 +5506,59 @@ 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
+ *
+ */
+EAPI Eina_Bool evas_object_image_animated_get(const Evas_Object *obj);
+
+/**
+ * Get the frame number of image object's file.
+ *
+ * @param obj Image object
+ * @return the number of frame
+ *
+ */
+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
+ */
+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
+ */
+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
+ *
+ */
+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
+ *
+ */
+EAPI void evas_object_image_animated_frame_set(Evas_Object *obj, int frame_num);
+
+/**
  * @defgroup Evas_Object_Text Text Object Functions
  *
  * Functions that operate on single line, single style text objects.
index 2c1dd85..847e402 100755 (executable)
@@ -1161,7 +1161,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)
      {
@@ -1185,7 +1185,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;
index 0bcb926..1336199 100644 (file)
@@ -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;
@@ -1846,6 +1847,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)
 {
@@ -1861,6 +1863,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)
 {
@@ -2988,6 +3136,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 */
index 6d5c620..300697c 100644 (file)
@@ -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);
 
index d374f47..0a4c7ae 100644 (file)
@@ -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)
 {
index 7a8984a..a210581 100644 (file)
@@ -351,6 +351,17 @@ _evas_common_rgba_image_surface_delete(Image_Entry *ie)
    else if (ie->data1)
      evas_cserve_image_free(ie);
 #endif   
+   if ( ie->flags.animated)
+     {
+        if (ie->frames)
+          {
+             Eina_List *l;
+             void *data;
+
+             EINA_LIST_FOREACH(ie->frames, l, data)
+               if (data) free(data);
+          }
+     }
    im->image.data = NULL;
    ie->allocated.w = 0;
    ie->allocated.h = 0;
index 9b846a3..24a4f2d 100644 (file)
@@ -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)
           {
index e75da14..e556985 100644 (file)
@@ -511,6 +511,7 @@ struct _Image_Entry_Flags
    Eina_Bool delete_me    : 1;
    Eina_Bool pending      : 1;
 #endif
+   Eina_Bool animated     : 1;
 };
 
 struct _Evas_Cache_Target
@@ -593,6 +594,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
index 5d3f6f7..b2f5310 100644 (file)
@@ -751,6 +751,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
@@ -758,6 +766,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
index 0cc2d53..b862515 100644 (file)
@@ -2899,6 +2899,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)
 {
@@ -3007,6 +3075,14 @@ module_open(Evas_Module *em)
    
    ORD(image_load_error_get);
    
+   /* animated feature */
+   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;
index f1ebc97..5396117 100644 (file)
@@ -651,6 +651,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__)
 {
@@ -1097,7 +1164,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 */
 };
 
index 465df6f..40253d4 100644 (file)
@@ -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
index 239a072..94b121e 100644 (file)
@@ -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
index 699e9c0..f107d42 100644 (file)
 
 #include <gif_lib.h>
 
+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
+{
+   int index;
+   Eina_Bool loaded       : 1;
+
+   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;
+   DATA32    *data;
+};
+
+static Eina_Bool evas_image_load_file_data_gif_internal(Image_Entry *ie, Gif_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, Gif_Frame **frame)
+{
+   Eina_List *l;
+   Gif_Frame *hit_frame;
+
+   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, Gif_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));
+}
+
+static Eina_Bool _evas_image_load_frame_graphic_info(Gif_Frame *frame, GifByteType  *ext)
+{
+   if (!frame || !ext) return EINA_FALSE;
+
+   /* transparent */
+   if ((ext[1] & 0x1) != 0)
+     frame->frame_info.transparent = ext[4];
+   else
+     frame->frame_info.transparent = -1;
+
+   frame->frame_info.input = (ext[1] >>1) & 0x1;
+   frame->frame_info.disposal = (ext[1] >>2) & 0x7;
+   frame->frame_info.delay = byte2_to_int(ext[2], ext[3]);
+}
+
+static Eina_Bool _evas_image_load_frame_image_des_info(GifFileType *gif, Gif_Frame *frame)
+{
+   if (!gif || !frame) return EINA_FALSE;
+   frame->image_des.x = gif->Image.Left;
+   frame->image_des.y = gif->Image.Top;
+   frame->image_des.w = gif->Image.Width;
+   frame->image_des.h = gif->Image.Height;
+   frame->image_des.interlace = gif->Image.Interlace;
+}
+
+static Eina_Bool _evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Gif_Frame *frame, int *error)
+{
+   int                 w;
+   int                 h;
+   int                 i,j;
+   int                 img_code;
+   int                 bg;
+   int                 r;
+   int                 g;
+   int                 b;
+   int                 alpha;
+   double              per;
+   double              per_inc;
+   ColorMapObject     *cmap;
+   GifByteType        *img;
+   GifRowType         *rows;
+   int                 intoffset[] = { 0, 4, 2, 1 };
+   int                 intjump[] = { 8, 8, 4, 2 };
+   size_t              siz;
+   int                 cache_w;
+   int                 cache_h;
+   DATA32             *ptr;
+
+   if (!gif || !frame) return EINA_FALSE;
+
+   w = gif->Image.Width;
+   h = gif->Image.Height;
+   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 = frame->frame_info.transparent;
+   siz = cache_w *cache_h * sizeof(DATA32);
+   frame->data = malloc(siz);
+   ptr = frame->data;
+   bg = gif->SBackGroundColor;
+   cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
+
+   per_inc = 100.0 / (((double)w) * h);
+   if (frame->index > 1)
+     {
+        /* get previous frame only frame index is bigger than 1 */
+        DATA32    *ptr_src;
+        Gif_Frame *new_frame = NULL;
+        int        cur_x, cur_y;
+        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 */
+        cur_x = frame->image_des.x;
+        cur_y = frame->image_des.y;
+        ptr = ptr + cache_w * cur_y;
+
+        for (i = 0; i < h; i++)
+          {
+             ptr = ptr + cur_x;
+             for (j = 0; j < 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 - (cur_x + w));
+          }
+     }
+   else
+     {
+        int cur_x = frame->image_des.x;
+        int cur_y = frame->image_des.y;
+        ptr = ptr + cache_w * cur_y;
+
+        for (i = 0; i < h; i++)
+          {
+             ptr = ptr + cur_x;
+             for (j = 0; j < 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 - (cur_x + w));
+          }
+     }
+
+   for (i = 0; i < h; i++)
+     {
+        free(rows[i]);
+     }
+   free(rows);
+   frame->loaded = EINA_TRUE;
+   return EINA_TRUE;
+error:
+   for (i = 0; i < h; i++)
+     {
+        free(rows[i]);
+     }
+   free(rows);
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_evas_image_load_frame(Image_Entry *ie, GifFileType *gif, Gif_Frame *frame, Frame_Load_Type type, int *error)
+{
+   GifRecordType       rec;
+   int                 gra_res = 0, img_res = 0;
+   Eina_Bool           res = EINA_FALSE;
+
+   if (!gif || !frame) return EINA_FALSE;
+   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, Gif_Frame *frame,  int *error)
+{
+   int w;
+   int h;
+   int dst_x;
+   int dst_y;
+   int i;
+   int j;
+   DATA32 *dst;
+   DATA32 *src;
+   int cache_w, cache_h;
+   size_t   siz;
+
+   cache_w = ie->w;
+   cache_h = ie->h;
+   w = frame->image_des.w;
+   h = frame->image_des.h;
+   dst_x = frame->image_des.x;
+   dst_y = 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 +455,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;
@@ -53,33 +483,59 @@ evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key
        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;
                }
-             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))
+             /* we have to count frame, so use DGifGetCode and skip decoding */
+             if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
               {
+                  /* PrintGifError(); */
                  DGifCloseFile(gif);
-                 if (IMG_TOO_BIG(w, h))
-                   *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
-                 else
-                   *error = EVAS_LOAD_ERROR_GENERIC;
+                  *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
                  return EINA_FALSE;
               }
-            done = 1;
+             while (img)
+               {
+                  img = NULL;
+                  DGifGetExtensionNext(gif, &img);
+               }
           }
         else if (rec == EXTENSION_RECORD_TYPE)
           {
@@ -90,10 +546,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 +573,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 +589,11 @@ 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;
+   Gif_Frame *frame = NULL;
 
 #ifndef __EMX__
    fd = open(file, O_RDONLY);
@@ -162,139 +613,221 @@ evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key
        *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
        return EINA_FALSE;
      }
-   do
+   if (!_evas_image_skip_frame(gif, frame_index-1))
      {
-        if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
+        close(fd);
+        *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+        return EINA_FALSE;
+     }
+
+   frame = malloc(sizeof (Gif_Frame));
+   if (!frame)
           {
-             /* PrintGifError(); */
-             rec = TERMINATE_RECORD_TYPE;
+        if (fd)
+          close(fd);
+        *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+        return EINA_FALSE;
           }
-        if ((rec == IMAGE_DESC_RECORD_TYPE) && (!done))
+
+   frame->index = frame_index;
+   if (!_evas_image_load_frame(ie,gif, frame, LOAD_FRAME_DATA_INFO,error))
           {
-             if (DGifGetImageDesc(gif) == GIF_ERROR)
-               {
-                  /* PrintGifError(); */
-                  rec = TERMINATE_RECORD_TYPE;
+        if (fd)
+          close(fd);
+        *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+        return EINA_FALSE;
+     }
+
+   ie->frames = eina_list_append(ie->frames, frame);
+   if (fd)
+     close(fd);
+   return EINA_TRUE;
                }
-             w = gif->Image.Width;
-             h = gif->Image.Height;
-             rows = malloc(h * sizeof(GifRowType *));
-             if (!rows)
+
+static Eina_Bool
+evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
                {
-                  DGifCloseFile(gif);
-                  return 0;
-               }
-             for (i = 0; i < h; i++)
+   int cur_frame_index;
+   Gif_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)))
                {
-                  rows[i] = NULL;
+        *error = EVAS_LOAD_ERROR_GENERIC;
+        return EINA_FALSE;
                }
-             for (i = 0; i < h; i++)
+
+   /* 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)
                {
-                  rows[i] = malloc(w * sizeof(GifPixelType));
-                  if (!rows[i])
+        if (frame->loaded)
+          evas_image_load_file_data_gif_internal(ie,frame,error);
+        else
                     {
-                       DGifCloseFile(gif);
-                       for (i = 0; i < h; i++)
+             int fd;
+             GifFileType        *gif;
+
+#ifndef __EMX__
+             fd = open(file, O_RDONLY);
+#else
+             fd = open(file, O_RDONLY | O_BINARY);
+#endif
+             if (fd < 0)
                          {
-                            if (rows[i])
+                  *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+                  return EINA_FALSE;
+               }
+
+             gif = DGifOpenFileHandle(fd);
+             if (!gif)
                               {
-                                 free(rows[i]);
+                  close(fd);
+                  *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+                  return EINA_FALSE;
                               }
-                         }
-                       free(rows);
-                      *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+             _evas_image_skip_frame(gif, cur_frame_index-1);
+             if (!_evas_image_load_frame(ie, gif, frame, LOAD_FRAME_DATA,error))
+               {
+                  close(fd);
+                  *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
                       return EINA_FALSE;
                     }
-               }
-             if (gif->Image.Interlace)
+             if (!evas_image_load_file_data_gif_internal(ie, frame, error))
                {
-                  for (i = 0; i < 4; i++)
-                    {
-                       for (j = intoffset[i]; j < h; j += intjump[i])
-                         {
-                            DGifGetLine(gif, rows[j], w);
+                  close(fd);
+                  *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+                  return EINA_FALSE;
                          }
+             return EINA_TRUE;
                     }
                }
+   /* current frame does is not exist */
              else
                {
-                  for (i = 0; i < h; i++)
+        if (!evas_image_load_specific_frame(ie, file, cur_frame_index, error))
                     {
-                       DGifGetLine(gif, rows[i], w);
+             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;
                }
-             done = 1;
+        return EINA_TRUE;
+     }
           }
-        else if (rec == EXTENSION_RECORD_TYPE)
+
+static double
+evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int start_frame, const int frame_num)
           {
-             int                 ext_code;
-             GifByteType        *ext;
+   int                 fd;
+   GifFileType        *gif;
+   GifRecordType       rec;
+   int                 done;
+   int                 current_frame = 1;
+   int                 remain_frames = frame_num;
+   double              duration = 0;
+   int                 frame_count = 0;
 
-             ext = NULL;
-             DGifGetExtension(gif, &ext_code, &ext);
-             while (ext)
+   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 ((ext_code == 0xf9) && (ext[1] & 1) && (alpha < 0))
-                    {
-                       alpha = (int)ext[4];
-                    }
-                  ext = NULL;
-                  DGifGetExtensionNext(gif, &ext);
+        close(fd);
+        return -1;
                }
+
+   do
+     {
+        if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
+          {
+             rec = TERMINATE_RECORD_TYPE;
           }
-   } while (rec != TERMINATE_RECORD_TYPE);
+        if (rec == IMAGE_DESC_RECORD_TYPE)
+          {
+             int                 img_code;
+             GifByteType        *img;
 
-   if (alpha >= 0) ie->flags.alpha = 1;
-   evas_cache_image_surface_alloc(ie, w, h);
-   if (!evas_cache_image_pixels(ie))
+             if (DGifGetImageDesc(gif) == GIF_ERROR)
+               {
+                  /* PrintGifError(); */
+                  rec = TERMINATE_RECORD_TYPE;
+     }
+             current_frame++;
+             /* we have to count frame, so use DGifGetCode and skip decoding */
+             if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
      {
-        DGifCloseFile(gif);
-        for (i = 0; i < h; i++)
+                  rec = TERMINATE_RECORD_TYPE;
+               }
+             while (img)
           {
-            free(rows[i]);
+                  img = NULL;
+                  DGifGetExtensionNext(gif, &img);
           }
-        free(rows);
-       *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
-       return EINA_FALSE;
      }
+        else if (rec == EXTENSION_RECORD_TYPE)
+          {
+             int                 ext_code;
+             GifByteType        *ext;
 
-   bg = gif->SBackGroundColor;
-   cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
-
-   ptr = evas_cache_image_pixels(ie);
-   per_inc = 100.0 / (((double)w) * h);
-
-   for (i = 0; i < h; i++)
+             ext = NULL;
+             DGifGetExtension(gif, &ext_code, &ext);
+             while (ext)
      {
-       for (j = 0; j < w; j++)
+                  if (ext_code == 0xf9) /* Graphic Control Extension */
          {
-           if (rows[i][j] == alpha)
+                       int *test = NULL;
+
+                       if ((current_frame  >= start_frame) && (current_frame <= frame_count))
              {
-               r = cmap->Colors[bg].Red;
-               g = cmap->Colors[bg].Green;
-               b = cmap->Colors[bg].Blue;
-               *ptr++ = 0x00ffffff & RGB_JOIN(r, g, b);
-             }
+                            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
-             {
-               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);
+                              duration += (double)frame_duration/100;
+                            remain_frames --;
              }
-           per += per_inc;
          }
+                  ext = NULL;
+                  DGifGetExtensionNext(gif, &ext);
      }
-   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
index 1885c15..17a7f7e 100644 (file)
@@ -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
index 673f262..f32dd75 100644 (file)
@@ -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
 };
 
 
index 001a2a0..fce6a1a 100644 (file)
@@ -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 */
index 45669fc..aa657b5 100644 (file)
@@ -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
index 9f66886..05b277c 100644 (file)
@@ -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
index 270afbb..b9bea91 100644 (file)
@@ -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;
index 393d6da..5168be5 100644 (file)
@@ -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
 };