1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fxcodec/codec/ccodec_gifmodule.h"
8 
9 #include "core/fxcodec/codec/codec_int.h"
10 #include "core/fxcodec/fx_codec.h"
11 #include "core/fxcodec/lgif/fx_gif.h"
12 #include "core/fxge/fx_dib.h"
13 
14 struct FXGIF_Context {
15   gif_decompress_struct_p gif_ptr;
16   void* parent_ptr;
17 
18   void* (*m_AllocFunc)(unsigned int);
19   void (*m_FreeFunc)(void*);
20 };
21 
22 extern "C" {
gif_alloc_func(unsigned int size)23 static void* gif_alloc_func(unsigned int size) {
24   return FX_Alloc(char, size);
25 }
gif_free_func(void * p)26 static void gif_free_func(void* p) {
27   FX_Free(p);
28 }
29 };
30 
gif_error_data(gif_decompress_struct_p gif_ptr,const FX_CHAR * err_msg)31 static void gif_error_data(gif_decompress_struct_p gif_ptr,
32                            const FX_CHAR* err_msg) {
33   FXSYS_strncpy((char*)gif_ptr->err_ptr, err_msg, GIF_MAX_ERROR_SIZE - 1);
34   longjmp(gif_ptr->jmpbuf, 1);
35 }
36 
gif_ask_buf_for_pal(gif_decompress_struct_p gif_ptr,int32_t pal_size)37 static uint8_t* gif_ask_buf_for_pal(gif_decompress_struct_p gif_ptr,
38                                     int32_t pal_size) {
39   FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;
40   CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;
41   return pModule->GetDelegate()->GifAskLocalPaletteBuf(
42       gif_get_frame_num(gif_ptr), pal_size);
43 }
44 
gif_record_current_position(gif_decompress_struct_p gif_ptr,uint32_t * cur_pos_ptr)45 static void gif_record_current_position(gif_decompress_struct_p gif_ptr,
46                                         uint32_t* cur_pos_ptr) {
47   FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;
48   CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;
49   pModule->GetDelegate()->GifRecordCurrentPosition(*cur_pos_ptr);
50 }
51 
gif_read_scanline(gif_decompress_struct_p gif_ptr,int32_t row_num,uint8_t * row_buf)52 static void gif_read_scanline(gif_decompress_struct_p gif_ptr,
53                               int32_t row_num,
54                               uint8_t* row_buf) {
55   FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;
56   CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;
57   pModule->GetDelegate()->GifReadScanline(row_num, row_buf);
58 }
59 
gif_get_record_position(gif_decompress_struct_p gif_ptr,uint32_t cur_pos,int32_t left,int32_t top,int32_t width,int32_t height,int32_t pal_num,void * pal_ptr,int32_t delay_time,bool user_input,int32_t trans_index,int32_t disposal_method,bool interlace)60 static bool gif_get_record_position(gif_decompress_struct_p gif_ptr,
61                                     uint32_t cur_pos,
62                                     int32_t left,
63                                     int32_t top,
64                                     int32_t width,
65                                     int32_t height,
66                                     int32_t pal_num,
67                                     void* pal_ptr,
68                                     int32_t delay_time,
69                                     bool user_input,
70                                     int32_t trans_index,
71                                     int32_t disposal_method,
72                                     bool interlace) {
73   FXGIF_Context* p = (FXGIF_Context*)gif_ptr->context_ptr;
74   CCodec_GifModule* pModule = (CCodec_GifModule*)p->parent_ptr;
75   return pModule->GetDelegate()->GifInputRecordPositionBuf(
76       cur_pos, FX_RECT(left, top, left + width, top + height), pal_num, pal_ptr,
77       delay_time, user_input, trans_index, disposal_method, interlace);
78 }
79 
CCodec_GifModule()80 CCodec_GifModule::CCodec_GifModule() {
81   memset(m_szLastError, 0, sizeof(m_szLastError));
82 }
83 
~CCodec_GifModule()84 CCodec_GifModule::~CCodec_GifModule() {}
85 
Start()86 FXGIF_Context* CCodec_GifModule::Start() {
87   FXGIF_Context* p = FX_Alloc(FXGIF_Context, 1);
88   if (!p)
89     return nullptr;
90 
91   FXSYS_memset(p, 0, sizeof(FXGIF_Context));
92   p->m_AllocFunc = gif_alloc_func;
93   p->m_FreeFunc = gif_free_func;
94   p->gif_ptr = nullptr;
95   p->parent_ptr = (void*)this;
96   p->gif_ptr = gif_create_decompress();
97   if (!p->gif_ptr) {
98     FX_Free(p);
99     return nullptr;
100   }
101   p->gif_ptr->context_ptr = (void*)p;
102   p->gif_ptr->err_ptr = m_szLastError;
103   p->gif_ptr->gif_error_fn = gif_error_data;
104   p->gif_ptr->gif_ask_buf_for_pal_fn = gif_ask_buf_for_pal;
105   p->gif_ptr->gif_record_current_position_fn = gif_record_current_position;
106   p->gif_ptr->gif_get_row_fn = gif_read_scanline;
107   p->gif_ptr->gif_get_record_position_fn = gif_get_record_position;
108   return p;
109 }
110 
Finish(FXGIF_Context * ctx)111 void CCodec_GifModule::Finish(FXGIF_Context* ctx) {
112   if (ctx) {
113     gif_destroy_decompress(&ctx->gif_ptr);
114     ctx->m_FreeFunc(ctx);
115   }
116 }
117 
ReadHeader(FXGIF_Context * ctx,int * width,int * height,int * pal_num,void ** pal_pp,int * bg_index,CFX_DIBAttribute * pAttribute)118 int32_t CCodec_GifModule::ReadHeader(FXGIF_Context* ctx,
119                                      int* width,
120                                      int* height,
121                                      int* pal_num,
122                                      void** pal_pp,
123                                      int* bg_index,
124                                      CFX_DIBAttribute* pAttribute) {
125   if (setjmp(ctx->gif_ptr->jmpbuf))
126     return 0;
127 
128   int32_t ret = gif_read_header(ctx->gif_ptr);
129   if (ret != 1)
130     return ret;
131 
132   *width = ctx->gif_ptr->width;
133   *height = ctx->gif_ptr->height;
134   *pal_num = ctx->gif_ptr->global_pal_num;
135   *pal_pp = ctx->gif_ptr->global_pal_ptr;
136   *bg_index = ctx->gif_ptr->bc_index;
137   return 1;
138 }
139 
LoadFrameInfo(FXGIF_Context * ctx,int * frame_num)140 int32_t CCodec_GifModule::LoadFrameInfo(FXGIF_Context* ctx, int* frame_num) {
141   if (setjmp(ctx->gif_ptr->jmpbuf))
142     return 0;
143 
144   int32_t ret = gif_get_frame(ctx->gif_ptr);
145   if (ret != 1)
146     return ret;
147 
148   *frame_num = gif_get_frame_num(ctx->gif_ptr);
149   return 1;
150 }
151 
LoadFrame(FXGIF_Context * ctx,int frame_num,CFX_DIBAttribute * pAttribute)152 int32_t CCodec_GifModule::LoadFrame(FXGIF_Context* ctx,
153                                     int frame_num,
154                                     CFX_DIBAttribute* pAttribute) {
155   if (setjmp(ctx->gif_ptr->jmpbuf))
156     return 0;
157 
158   int32_t ret = gif_load_frame(ctx->gif_ptr, frame_num);
159   if (ret == 1) {
160     if (pAttribute) {
161       pAttribute->m_nGifLeft =
162           (*ctx->gif_ptr->img_ptr_arr_ptr)[frame_num]->image_info_ptr->left;
163       pAttribute->m_nGifTop =
164           (*ctx->gif_ptr->img_ptr_arr_ptr)[frame_num]->image_info_ptr->top;
165       pAttribute->m_fAspectRatio = ctx->gif_ptr->pixel_aspect;
166       if (ctx->gif_ptr->cmt_data_ptr) {
167         const uint8_t* buf =
168             (const uint8_t*)ctx->gif_ptr->cmt_data_ptr->GetBuffer(0);
169         uint32_t len = ctx->gif_ptr->cmt_data_ptr->GetLength();
170         if (len > 21) {
171           uint8_t size = *buf++;
172           if (size) {
173             pAttribute->m_strAuthor = CFX_ByteString(buf, size);
174           } else {
175             pAttribute->m_strAuthor.clear();
176           }
177           buf += size;
178           size = *buf++;
179           if (size == 20) {
180             FXSYS_memcpy(pAttribute->m_strTime, buf, size);
181           }
182         }
183       }
184     }
185   }
186   return ret;
187 }
188 
GetAvailInput(FXGIF_Context * ctx,uint8_t ** avail_buf_ptr)189 uint32_t CCodec_GifModule::GetAvailInput(FXGIF_Context* ctx,
190                                          uint8_t** avail_buf_ptr) {
191   return gif_get_avail_input(ctx->gif_ptr, avail_buf_ptr);
192 }
193 
Input(FXGIF_Context * ctx,const uint8_t * src_buf,uint32_t src_size)194 void CCodec_GifModule::Input(FXGIF_Context* ctx,
195                              const uint8_t* src_buf,
196                              uint32_t src_size) {
197   gif_input_buffer(ctx->gif_ptr, (uint8_t*)src_buf, src_size);
198 }
199