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