Gif loader didn't initialize frame buffer of first frame.
[profile/ivi/evas.git] / src / modules / loaders / gif / evas_image_load_gif.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8
9 #include <gif_lib.h>
10
11 typedef struct _Gif_Frame Gif_Frame;
12
13 typedef enum _Frame_Load_Type
14 {
15    LOAD_FRAME_NONE = 0,
16    LOAD_FRAME_INFO = 1,
17    LOAD_FRAME_DATA = 2,
18    LOAD_FRAME_DATA_INFO = 3
19 } Frame_Load_Type;
20
21 struct _Gif_Frame
22 {
23    struct {
24       /* Image descriptor */
25       int        x;
26       int        y;
27       int        w;
28       int        h;
29       int        interlace;
30    } image_des;
31
32    struct {
33       /* Graphic Control*/
34       int        disposal;
35       int        transparent;
36       int        delay;
37       int        input;
38    } frame_info;
39 };
40
41 static Eina_Bool evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error);
42
43 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);
44 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);
45 static double evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, int start_frame, int frame_num) ;
46 static Eina_Bool evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error);
47
48 static Evas_Image_Load_Func evas_image_load_gif_func =
49 {
50   EINA_TRUE,
51   evas_image_load_file_head_gif,
52   evas_image_load_file_data_gif,
53   evas_image_load_frame_duration_gif,
54   EINA_FALSE
55 };
56 #define byte2_to_int(a,b)         (((b)<<8)|(a))
57
58 #define FRAME_MAX 1024
59
60 /* find specific frame in image entry */
61 static Eina_Bool
62 _find_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame)
63 {
64    Eina_List *l;
65    Image_Entry_Frame *hit_frame = NULL;
66
67    if (!ie) return EINA_FALSE;
68    if (!ie->frames) return EINA_FALSE;
69
70    EINA_LIST_FOREACH(ie->frames, l, hit_frame)
71      {
72         if (hit_frame->index == frame_index)
73           {
74              *frame = hit_frame;
75              return EINA_TRUE;
76           }
77      }
78    return EINA_FALSE;
79 }
80
81 static Eina_Bool
82 _find_close_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame)
83 {
84   int i;
85   Eina_Bool hit = EINA_FALSE;
86   i = frame_index -1;
87
88   if (!ie) return EINA_FALSE;
89   if (!ie->frames) return EINA_FALSE;
90
91   for (; i > 0; i--)
92     {
93        hit = _find_frame(ie, i, frame);
94        if (hit)
95          return  EINA_TRUE;
96     }
97   return EINA_FALSE;
98 }
99
100 static Eina_Bool
101 _evas_image_skip_frame(GifFileType *gif, int frame)
102 {
103    int                 remain_frame = 0;
104    GifRecordType       rec;
105
106    if (!gif) return EINA_FALSE;
107    if (frame == 0) return EINA_TRUE; /* no need to skip */
108    if (frame < 0 || frame > FRAME_MAX) return EINA_FALSE;
109
110    remain_frame = frame;
111
112    do
113      {
114         if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
115
116         if (rec == EXTENSION_RECORD_TYPE)
117           {
118              int                 ext_code;
119              GifByteType        *ext;
120
121              ext = NULL;
122              DGifGetExtension(gif, &ext_code, &ext);
123              while (ext)
124                { /*skip extention */
125                   ext = NULL;
126                   DGifGetExtensionNext(gif, &ext);
127                }
128           }
129
130         if (rec == IMAGE_DESC_RECORD_TYPE)
131           {
132              int                 img_code;
133              GifByteType        *img;
134
135              if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE;
136
137              remain_frame --;
138              /* we have to count frame, so use DGifGetCode and skip decoding */
139              if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) return EINA_FALSE;
140
141              while (img)
142                {
143                   img = NULL;
144                   DGifGetCodeNext(gif, &img);
145                }
146              if (remain_frame < 1) return EINA_TRUE;
147           }
148         if (rec == TERMINATE_RECORD_TYPE) return EINA_FALSE;  /* end of file */
149
150      } while ((rec != TERMINATE_RECORD_TYPE) && (remain_frame > 0));
151    return EINA_FALSE;
152 }
153
154 static Eina_Bool
155 _evas_image_load_frame_graphic_info(Image_Entry_Frame *frame, GifByteType  *ext)
156 {
157    Gif_Frame *gif_frame = NULL;
158    if ((!frame) || (!ext)) return EINA_FALSE;
159
160    gif_frame = (Gif_Frame *) frame->info;
161
162    /* transparent */
163    if ((ext[1] & 0x1) != 0)
164      gif_frame->frame_info.transparent = ext[4];
165    else
166      gif_frame->frame_info.transparent = -1;
167
168    gif_frame->frame_info.input = (ext[1] >>1) & 0x1;
169    gif_frame->frame_info.disposal = (ext[1] >>2) & 0x7;
170    gif_frame->frame_info.delay = byte2_to_int(ext[2], ext[3]);
171    return EINA_TRUE;
172 }
173
174 static Eina_Bool
175 _evas_image_load_frame_image_des_info(GifFileType *gif, Image_Entry_Frame *frame)
176 {
177    Gif_Frame *gif_frame = NULL;
178    if ((!gif) || (!frame)) return EINA_FALSE;
179
180    gif_frame = (Gif_Frame *) frame->info;
181    gif_frame->image_des.x = gif->Image.Left;
182    gif_frame->image_des.y = gif->Image.Top;
183    gif_frame->image_des.w = gif->Image.Width;
184    gif_frame->image_des.h = gif->Image.Height;
185    gif_frame->image_des.interlace = gif->Image.Interlace;
186    return EINA_TRUE;
187 }
188
189 static Eina_Bool
190 _evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, int *error)
191 {
192    int                 w;
193    int                 h;
194    int                 x;
195    int                 y;
196    int                 i,j;
197    int                 bg;
198    int                 r;
199    int                 g;
200    int                 b;
201    int                 alpha;
202    double              per;
203    double              per_inc;
204    ColorMapObject     *cmap;
205    GifRowType         *rows;
206    GifPixelType       *tmp = NULL; /*for skip gif line */
207    int                 intoffset[] = { 0, 4, 2, 1 };
208    int                 intjump[] = { 8, 8, 4, 2 };
209    size_t              siz;
210    int                 cache_w;
211    int                 cache_h;
212    int                 cur_h;
213    int                 cur_w;
214    int                 disposal = 0;
215    int                 bg_val = 0;
216    DATA32             *ptr;
217    Gif_Frame          *gif_frame = NULL;
218    /* for scale down decoding */
219    int                 scale_ratio = 1;
220    int                 scale_w, scale_h, scale_x, scale_y;
221
222    if ((!gif) || (!frame)) return EINA_FALSE;
223
224    gif_frame = (Gif_Frame *) frame->info;
225    w = gif->Image.Width;
226    h = gif->Image.Height;
227    x = gif->Image.Left;
228    y = gif->Image.Top;
229    cache_w = ie->w;
230    cache_h = ie->h;
231
232    /* if user don't set scale down, default scale_ratio is 1 */
233    if (ie->load_opts.scale_down_by > 1) scale_ratio = ie->load_opts.scale_down_by;
234    scale_w = w / scale_ratio;
235    scale_h = h / scale_ratio;
236    scale_x = x / scale_ratio;
237    scale_y = y / scale_ratio;
238
239    rows = malloc(scale_h * sizeof(GifRowType *));
240
241    if (!rows)
242      {
243         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
244         return EINA_FALSE;
245      }
246    for (i = 0; i < scale_h; i++)
247      {
248         rows[i] = NULL;
249      }
250    /* alloc memory according to scaled size */
251    for (i = 0; i < scale_h; i++)
252      {
253         rows[i] = malloc(w * sizeof(GifPixelType));
254         if (!rows[i])
255           {
256              for (i = 0; i < scale_h; i++)
257                {
258                   if (rows[i])
259                     {
260                        free(rows[i]);
261                     }
262                }
263              free(rows);
264              *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
265              return EINA_FALSE;
266           }
267      }
268
269    if (scale_ratio > 1)
270      {
271         tmp = malloc(w * sizeof(GifPixelType));
272         if (!tmp)
273           {
274              *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
275              goto error;
276           }
277      }
278
279    if (gif->Image.Interlace)
280      {
281         Eina_Bool multiple;
282         int scale_j;
283         for (i = 0; i < 4; i++)
284           {
285              for (j = intoffset[i]; j < h; j += intjump[i])
286                {
287                   scale_j = j / scale_ratio;
288                   multiple = ((j % scale_ratio) ? EINA_FALSE : EINA_TRUE);
289
290                   if (multiple && (scale_j < scale_h))
291                     DGifGetLine(gif, rows[scale_j], w);
292                   else
293                     DGifGetLine(gif, tmp, w);
294                }
295           }
296      }
297    else
298      {
299         for (i = 0; i < scale_h; i++)
300           {
301              if (DGifGetLine(gif, rows[i], w) != GIF_OK)
302                {
303                   *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
304                   goto error;
305               }
306              if (scale_ratio > 1)
307                {
308                   /* we use down sample method for scale down, so skip other line */
309                   for (j = 0; j < (scale_ratio - 1); j++)
310                     {
311                        if (DGifGetLine(gif, tmp, w) != GIF_OK)
312                          {
313                             *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
314                             goto error;
315                          }
316                     }
317                }
318           }
319      }
320
321    if (scale_ratio > 1)
322      {
323         if (tmp) free(tmp);
324         tmp = NULL;
325      }
326
327    alpha = gif_frame->frame_info.transparent;
328    siz = cache_w *cache_h * sizeof(DATA32);
329    frame->data = malloc(siz);
330    if (!frame->data)
331      {
332         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
333         goto error;
334      }
335    ptr = frame->data;
336    bg = gif->SBackGroundColor;
337    cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
338
339    if (!cmap)
340      {
341         DGifCloseFile(gif);
342         for (i = 0; i < scale_h; i++)
343           {
344              free(rows[i]);
345           }
346         free(rows);
347         if (frame->data) free(frame->data);
348         *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
349         return EINA_FALSE;
350      }
351
352    /* get the background value */
353    r = cmap->Colors[bg].Red;
354    g = cmap->Colors[bg].Green;
355    b = cmap->Colors[bg].Blue;
356    bg_val =  ARGB_JOIN(0xff, r, g, b);
357
358    per_inc = 100.0 / (((double)w) * h);
359    cur_h = scale_h;
360    cur_w = scale_w;
361
362    if (cur_h > cache_h) cur_h = cache_h;
363    if (cur_w > cache_w) cur_w = cache_w;
364
365    if (frame->index > 1)
366      {
367         /* get previous frame only frame index is bigger than 1 */
368         DATA32            *ptr_src;
369         Image_Entry_Frame *new_frame = NULL;
370         int                cur_frame = frame->index;
371         int                start_frame = 1;
372
373         if (_find_close_frame(ie, cur_frame, &new_frame))
374           start_frame = new_frame->index + 1;
375
376         if ((start_frame < 1) || (start_frame > cur_frame))
377           {
378              *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
379              goto error;
380           }
381         /* load previous frame of cur_frame */
382         for (j = start_frame; j < cur_frame ; j++)
383           {
384              if (!evas_image_load_specific_frame(ie, ie->file, j, error))
385                {
386                   *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
387                   goto error;
388                }
389           }
390         if (!_find_frame(ie, cur_frame - 1, &new_frame))
391           {
392              *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
393              goto error;
394           }
395         else
396           {
397              Gif_Frame *gif_frame2 = NULL;
398              ptr_src = new_frame->data;
399              if (new_frame->info)
400                {
401                   gif_frame2 = (Gif_Frame *)(new_frame->info);
402                   disposal = gif_frame2->frame_info.disposal;
403                }
404              switch(disposal) /* we only support disposal flag 0,1,2 */
405                {
406                 case 1: /* Do not dispose. need previous frame*/
407                   memcpy(ptr, ptr_src, siz);
408                   /* only decoding image descriptor's region */
409                   ptr = ptr + cache_w * scale_y;
410
411                   for (i = 0; i < cur_h; i++)
412                     {
413                        ptr = ptr + scale_x;
414                        for (j = 0; j < cur_w; j++)
415                          {
416                             if (rows[i][j * scale_ratio] == alpha)
417                               {
418                                  ptr++ ;
419                               }
420                             else
421                               {
422                                  r = cmap->Colors[rows[i][j * scale_ratio]].Red;
423                                  g = cmap->Colors[rows[i][j * scale_ratio]].Green;
424                                  b = cmap->Colors[rows[i][j * scale_ratio]].Blue;
425                                  *ptr++ = ARGB_JOIN(0xff, r, g, b);
426                               }
427                             per += per_inc;
428                          }
429                        ptr = ptr + (cache_w - (scale_x + cur_w));
430                     }
431                   break;
432                 case 2: /* Restore to background color */
433                    memcpy(ptr, ptr_src, siz);
434                    /* composite frames */
435                    for (i = 0; i < cache_h; i++)
436                     {
437                        if ((i < scale_y) || (i >= (scale_y + cur_h)))
438                          {
439                             for (j = 0; j < cache_w; j++)
440                               {
441                                  *ptr = bg_val;
442                                  ptr++;
443                               }
444                          }
445                        else
446                          {
447                             int i1, j1;
448                             i1 = i - scale_y;
449
450                             for (j = 0; j < cache_w; j++)
451                               {
452                                  j1 = j - scale_x;
453                                  if ((j < scale_x) || (j >= (scale_x + cur_w)))
454                                    {
455                                       *ptr = bg_val;
456                                       ptr++;
457                                    }
458                                  else
459                                    {
460                                       r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
461                                       g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
462                                       b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
463                                       *ptr++ = ARGB_JOIN(0xff, r, g, b);
464                                    }
465                               }
466                          }
467                     }
468                    break;
469                 case 0: /* No disposal specified */
470                 default:
471                    memset(ptr, 0, siz);
472                    for (i = 0; i < cache_h; i++)
473                      {
474                         if ((i < scale_y) || (i >= (scale_y + cur_h)))
475                           {
476                              for (j = 0; j < cache_w; j++)
477                                {
478                                   *ptr = bg_val;
479                                   ptr++;
480                                }
481                           }
482                         else
483                           {
484                              int i1, j1;
485                              i1 = i - scale_y;
486
487                              for (j = 0; j < cache_w; j++)
488                                {
489                                   j1 = j - scale_x;
490                                   if ((j < scale_x) || (j >= (scale_x + cur_w)))
491                                     {
492                                        *ptr = bg_val;
493                                        ptr++;
494                                     }
495                                   else
496                                     {
497                                        r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
498                                        g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
499                                        b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
500                                        *ptr++ = ARGB_JOIN(0xff, r, g, b);
501                                     }
502                                }
503                           }
504                      }
505                    break;
506                }
507           }
508      }
509    else /* first frame decoding */
510      {
511         memset(ptr, 0, siz);
512
513         /* fill background color */
514         for (i = 0; i < cache_h; i++)
515           {
516              /* the row's of logical screen not overap with frame */
517              if ((i < scale_y) || (i >= (scale_y + cur_h)))
518                {
519                   for (j = 0; j < cache_w; j++)
520                     {
521                        *ptr = bg_val;
522                        ptr++;
523                     }
524                }
525              else
526                {
527                   int i1, j1;
528                   i1 = i -scale_y;
529
530                   for (j = 0; j < cache_w; j++)
531                     {
532                        j1 = j - scale_x;
533                        if ((j < scale_x) || (j >= (scale_x + cur_w)))
534                          {
535                             *ptr = bg_val;
536                             ptr++;
537                          }
538                        else
539                          {
540                             if (rows[i1][j1] == alpha)
541                               {
542                                  ptr++ ;
543                               }
544                             else
545                               {
546                                  r = cmap->Colors[rows[i1][j1]].Red;
547                                  g = cmap->Colors[rows[i1][j1]].Green;
548                                  b = cmap->Colors[rows[i1][j1]].Blue;
549                                  *ptr++ = ARGB_JOIN(0xff, r, g, b);
550                               }
551                          }
552                     }
553                }
554           }
555      }
556
557    for (i = 0; i < scale_h; i++)
558      {
559         if (rows[i]) free(rows[i]);
560      }
561    if (rows) free(rows);
562    frame->loaded = EINA_TRUE;
563    return EINA_TRUE;
564 error:
565    for (i = 0; i < scale_h; i++)
566      {
567         if (rows[i]) free(rows[i]);
568      }
569    if (rows) free(rows);
570    if (tmp) free(tmp);
571    return EINA_FALSE;
572 }
573
574 static Eina_Bool
575 _evas_image_load_frame(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, Frame_Load_Type type, int *error)
576 {
577    GifRecordType       rec;
578    int                 gra_res = 0, img_res = 0;
579    Eina_Bool           res = EINA_FALSE;
580    Gif_Frame          *gif_frame = NULL;
581
582    if ((!gif) || (!frame)) return EINA_FALSE;
583    gif_frame = (Gif_Frame *) frame->info;
584
585    if (type > LOAD_FRAME_DATA_INFO) return EINA_FALSE;
586    
587    do
588      {
589         if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
590         if (rec == IMAGE_DESC_RECORD_TYPE)
591           {
592              img_res++;
593              break;
594           }
595         else if (rec == EXTENSION_RECORD_TYPE)
596           {
597              int           ext_code;
598              GifByteType  *ext;
599
600              ext = NULL;
601              DGifGetExtension(gif, &ext_code, &ext);
602              while (ext)
603                {
604                   if (ext_code == 0xf9) /* Graphic Control Extension */
605                     {
606                        gra_res++;
607                        /* fill frame info */
608                        if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO))
609                          _evas_image_load_frame_graphic_info(frame,ext);
610                     }
611                   ext = NULL;
612                   DGifGetExtensionNext(gif, &ext);
613                }
614           }
615      } while ((rec != TERMINATE_RECORD_TYPE) && (img_res == 0));
616    if (img_res != 1) return EINA_FALSE;
617    if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE;
618    if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO))
619      _evas_image_load_frame_image_des_info(gif, frame);
620
621    if ((type == LOAD_FRAME_DATA) || (type == LOAD_FRAME_DATA_INFO))
622      {
623         res = _evas_image_load_frame_image_data(ie, gif,frame, error);
624         if (!res) return EINA_FALSE;
625      }
626    return EINA_TRUE;
627 }
628
629
630 /* set frame data to cache entry's data */
631 static Eina_Bool
632 evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error)
633 {
634    int        w;
635    int        h;
636    int        dst_x;
637    int        dst_y;
638    DATA32    *dst;
639    DATA32    *src;
640    int        cache_w, cache_h;
641    size_t     siz;
642    Gif_Frame *gif_frame = NULL;
643
644    gif_frame = (Gif_Frame *) frame->info;
645    cache_w = ie->w;
646    cache_h = ie->h;
647    w = gif_frame->image_des.w;
648    h = gif_frame->image_des.h;
649    dst_x = gif_frame->image_des.x;
650    dst_y = gif_frame->image_des.y;
651
652    src = frame->data;
653
654    if (!evas_cache_image_pixels(ie))
655      {
656         evas_cache_image_surface_alloc(ie, cache_w, cache_h);
657      }
658
659    if (!evas_cache_image_pixels(ie))
660      {
661         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
662         return EINA_FALSE;
663      }
664
665    /* only copy real frame part */
666    siz = cache_w * cache_h *  sizeof(DATA32);
667    dst = evas_cache_image_pixels(ie);
668
669    memcpy(dst, src, siz);
670
671    evas_common_image_premul(ie);
672
673    *error = EVAS_LOAD_ERROR_NONE;
674    return EINA_TRUE;
675 }
676
677 static Eina_Bool
678 evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
679 {
680    int                 fd;
681    GifFileType        *gif;
682    GifRecordType       rec;
683    int                 w;
684    int                 h;
685    int                 alpha;
686    int                 loop_count = -1;
687
688    w = 0;
689    h = 0;
690    alpha = -1;
691
692 #ifndef __EMX__
693    fd = open(file, O_RDONLY);
694 #else
695    fd = open(file, O_RDONLY | O_BINARY);
696 #endif
697    if (fd < 0)
698      {
699         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
700         return EINA_FALSE;
701      }
702
703    gif = DGifOpenFileHandle(fd);
704    if (!gif)
705      {
706         if (fd) close(fd);
707         *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
708         return EINA_FALSE;
709      }
710
711    /* check logical screen size */
712    w = gif->SWidth;
713    h = gif->SHeight;
714    /* support scale down feture in gif*/
715    if (ie->load_opts.scale_down_by > 1)
716      {
717         w /= ie->load_opts.scale_down_by;
718         h /= ie->load_opts.scale_down_by;
719      }
720
721    if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
722        IMG_TOO_BIG(w, h))
723      {
724         DGifCloseFile(gif);
725         if (IMG_TOO_BIG(w, h))
726           *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
727         else
728           *error = EVAS_LOAD_ERROR_GENERIC;
729         return EINA_FALSE;
730      }
731    ie->w = w;
732    ie->h = h;
733
734    do
735      {
736         if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
737           {
738              /* PrintGifError(); */
739              DGifCloseFile(gif);
740              *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
741              return EINA_FALSE;
742           }
743
744         /* image descript info */
745         if (rec == IMAGE_DESC_RECORD_TYPE)
746           {
747              int img_code;
748              GifByteType *img;
749
750              if (DGifGetImageDesc(gif) == GIF_ERROR)
751                {
752                   /* PrintGifError(); */
753                   DGifCloseFile(gif);
754                   *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
755                   return EINA_FALSE;
756                }
757              /* we have to count frame, so use DGifGetCode and skip decoding */
758              if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
759                {
760                   /* PrintGifError(); */
761                   DGifCloseFile(gif);
762                   *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
763                   return EINA_FALSE;
764                }
765              while (img)
766                {
767                   img = NULL;
768                   DGifGetCodeNext(gif, &img);
769                }
770           }
771         else if (rec == EXTENSION_RECORD_TYPE)
772           {
773              int                 ext_code;
774              GifByteType        *ext;
775
776              ext = NULL;
777              DGifGetExtension(gif, &ext_code, &ext);
778              while (ext)
779                {
780                   if (ext_code == 0xf9) /* Graphic Control Extension */
781                     {
782                        if ((ext[1] & 1) && (alpha < 0)) alpha = (int)ext[4];
783                     }
784                   else if (ext_code == 0xff) /* application extension */
785                     {
786                        if (!strncmp ((char*)(&ext[1]), "NETSCAPE2.0", 11) ||
787                            !strncmp ((char*)(&ext[1]), "ANIMEXTS1.0", 11))
788                          {
789                             ext=NULL;
790                             DGifGetExtensionNext(gif, &ext);
791
792                             if (ext[1] == 0x01)
793                               {
794                                  loop_count = ext[2] + (ext[3] << 8);
795                                  if (loop_count > 0) loop_count++;
796                               }
797                          }
798                      }
799
800                   ext = NULL;
801                   DGifGetExtensionNext(gif, &ext);
802                }
803           }
804    } while (rec != TERMINATE_RECORD_TYPE);
805
806    if (alpha >= 0) ie->flags.alpha = 1;
807
808    if (gif->ImageCount > 1)
809      {
810         ie->flags.animated = 1;
811         ie->loop_count = loop_count;
812         ie->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP;
813         ie->frame_count = gif->ImageCount;
814         ie->frames = NULL;
815      }
816
817    DGifCloseFile(gif);
818    *error = EVAS_LOAD_ERROR_NONE;
819    return EINA_TRUE;
820 }
821
822 static Eina_Bool
823 evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error)
824 {
825    int                fd;
826    GifFileType       *gif;
827    Image_Entry_Frame *frame = NULL;
828    Gif_Frame         *gif_frame = NULL;
829
830 #ifndef __EMX__
831    fd = open(file, O_RDONLY);
832 #else
833    fd = open(file, O_RDONLY | O_BINARY);
834 #endif
835    if (fd < 0)
836      {
837         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
838         return EINA_FALSE;
839      }
840
841    gif = DGifOpenFileHandle(fd);
842    if (!gif)
843      {
844         if (fd) close(fd);
845         *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
846         return EINA_FALSE;
847      }
848    if (!_evas_image_skip_frame(gif, frame_index-1))
849      {
850         if (fd) close(fd);
851         *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
852         return EINA_FALSE;
853      }
854
855    frame = malloc(sizeof (Image_Entry_Frame));
856    if (!frame)
857      {
858         if (fd) close(fd);
859         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
860         return EINA_FALSE;
861      }
862
863    gif_frame = malloc(sizeof (Gif_Frame));
864    if (!gif_frame)
865      {
866         if (fd) close(fd);
867         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
868         return EINA_FALSE;
869      }
870    frame->info = gif_frame;
871    frame->index = frame_index;
872    if (!_evas_image_load_frame(ie,gif, frame, LOAD_FRAME_DATA_INFO,error))
873      {
874         if (fd) close(fd);
875         *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
876         return EINA_FALSE;
877      }
878
879    ie->frames = eina_list_append(ie->frames, frame);
880    DGifCloseFile(gif);
881    return EINA_TRUE;
882 }
883
884 static Eina_Bool
885 evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
886 {
887    int                cur_frame_index;
888    Image_Entry_Frame *frame = NULL;
889    Eina_Bool          hit;
890
891    if(!ie->flags.animated)
892      cur_frame_index = 1;
893    else
894      cur_frame_index = ie->cur_frame;
895
896    if ((ie->flags.animated) &&
897        ((cur_frame_index <0) || (cur_frame_index > FRAME_MAX) || (cur_frame_index > ie->frame_count)))
898      {
899         *error = EVAS_LOAD_ERROR_GENERIC;
900         return EINA_FALSE;
901      }
902
903    /* first time frame is set to be 0. so default is 1 */
904    if (cur_frame_index == 0) cur_frame_index++;
905
906    /* Check current frame exists in hash table */
907    hit = _find_frame(ie, cur_frame_index, &frame);
908
909    /* if current frame exist in has table, check load flag */
910    if (hit)
911      {
912         if (frame->loaded)
913           evas_image_load_file_data_gif_internal(ie,frame,error);
914         else
915           {
916              int           fd;
917              GifFileType  *gif;
918
919 #ifndef __EMX__
920              fd = open(file, O_RDONLY);
921 #else
922              fd = open(file, O_RDONLY | O_BINARY);
923 #endif
924              if (fd < 0)
925                {
926                   *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
927                   return EINA_FALSE;
928                }
929
930              gif = DGifOpenFileHandle(fd);
931              if (!gif)
932                {
933                   if (fd) close(fd);
934                   *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
935                   return EINA_FALSE;
936                }
937              _evas_image_skip_frame(gif, cur_frame_index-1);
938              if (!_evas_image_load_frame(ie, gif, frame, LOAD_FRAME_DATA,error))
939                {
940                   if (fd) close(fd);
941                   *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
942                   return EINA_FALSE;
943                }
944              if (!evas_image_load_file_data_gif_internal(ie, frame, error))
945                {
946                   if (fd) close(fd);
947                   *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
948                   return EINA_FALSE;
949                }
950              DGifCloseFile(gif);
951              *error = EVAS_LOAD_ERROR_NONE;
952              return EINA_TRUE;
953           }
954      }
955    /* current frame does is not exist */
956    else
957      {
958         if (!evas_image_load_specific_frame(ie, file, cur_frame_index, error))
959           {
960              return EINA_FALSE;
961           }
962         hit = EINA_FALSE;
963         frame = NULL;
964         hit = _find_frame(ie, cur_frame_index, &frame);
965         if (!hit) return EINA_FALSE;
966         if (!evas_image_load_file_data_gif_internal(ie, frame, error))
967           {
968              *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
969              return EINA_FALSE;
970           }
971         return EINA_TRUE;
972      }
973    return EINA_FALSE;
974 }
975
976 static double
977 evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int start_frame, const int frame_num)
978 {
979    int                 fd;
980    GifFileType        *gif;
981    GifRecordType       rec;
982    int                 done;
983    int                 current_frame = 1;
984    int                 remain_frames = frame_num;
985    double              duration = 0;
986    int                 frame_count = 0;
987
988    frame_count = ie->frame_count;
989
990    if (!ie->flags.animated) return -1;
991    if ((start_frame + frame_num) > frame_count) return -1;
992    if (frame_num < 0) return -1;
993
994    done = 0;
995
996 #ifndef __EMX__
997    fd = open(file, O_RDONLY);
998 #else
999    fd = open(file, O_RDONLY | O_BINARY);
1000 #endif
1001    if (fd < 0) return -1;
1002
1003    gif = DGifOpenFileHandle(fd);
1004    if (!gif)
1005      {
1006         if (fd) close(fd);
1007         return -1;
1008      }
1009
1010    do
1011      {
1012         if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
1013           {
1014              rec = TERMINATE_RECORD_TYPE;
1015           }
1016         if (rec == IMAGE_DESC_RECORD_TYPE)
1017           {
1018              int                 img_code;
1019              GifByteType        *img;
1020
1021              if (DGifGetImageDesc(gif) == GIF_ERROR)
1022                {
1023                   /* PrintGifError(); */
1024                   rec = TERMINATE_RECORD_TYPE;
1025                }
1026              current_frame++;
1027              /* we have to count frame, so use DGifGetCode and skip decoding */
1028              if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
1029                {
1030                   rec = TERMINATE_RECORD_TYPE;
1031                }
1032              while (img)
1033                {
1034                   img = NULL;
1035                   DGifGetExtensionNext(gif, &img);
1036                }
1037           }
1038         else if (rec == EXTENSION_RECORD_TYPE)
1039           {
1040              int                 ext_code;
1041              GifByteType        *ext;
1042
1043              ext = NULL;
1044              DGifGetExtension(gif, &ext_code, &ext);
1045              while (ext)
1046                {
1047                   if (ext_code == 0xf9) /* Graphic Control Extension */
1048                     {
1049                        if ((current_frame  >= start_frame) && (current_frame <= frame_count))
1050                          {
1051                             int frame_duration = 0;
1052                             if (remain_frames < 0) break;
1053                             frame_duration = byte2_to_int (ext[2], ext[3]);
1054                             if (frame_duration == 0)
1055                               duration += 0.1;
1056                             else
1057                               duration += (double)frame_duration/100;
1058                             remain_frames --;
1059                          }
1060                     }
1061                   ext = NULL;
1062                   DGifGetExtensionNext(gif, &ext);
1063                }
1064          }
1065      } while (rec != TERMINATE_RECORD_TYPE);
1066
1067    DGifCloseFile(gif);
1068    return duration;
1069 }
1070
1071 static int
1072 module_open(Evas_Module *em)
1073 {
1074    if (!em) return 0;
1075    em->functions = (void *)(&evas_image_load_gif_func);
1076    return 1;
1077 }
1078
1079 static void
1080 module_close(Evas_Module *em __UNUSED__)
1081 {
1082 }
1083
1084 static Evas_Module_Api evas_modapi =
1085 {
1086   EVAS_MODULE_API_VERSION,
1087   "gif",
1088   "none",
1089   {
1090     module_open,
1091     module_close
1092   }
1093 };
1094
1095 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, gif);
1096
1097 #ifndef EVAS_STATIC_BUILD_GIF
1098 EVAS_EINA_MODULE_DEFINE(image_loader, gif);
1099 #endif