Home | History | Annotate | Download | only in gif
      1 // Copyright 2017 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/gif/cfx_gifcontext.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 
     12 #include "core/fxcodec/codec/ccodec_gifmodule.h"
     13 #include "core/fxcodec/gif/cfx_gif.h"
     14 #include "third_party/base/ptr_util.h"
     15 #include "third_party/base/stl_util.h"
     16 
     17 namespace {
     18 
     19 const int32_t s_gif_interlace_step[4] = {8, 8, 4, 2};
     20 
     21 }  // namespace
     22 
     23 CFX_GifContext::CFX_GifContext(CCodec_GifModule* gif_module,
     24                                CCodec_GifModule::Delegate* delegate)
     25     : gif_module_(gif_module),
     26       delegate_(delegate),
     27       global_pal_exp_(0),
     28       img_row_offset_(0),
     29       img_row_avail_size_(0),
     30       avail_in_(0),
     31       decode_status_(GIF_D_STATUS_SIG),
     32       skip_size_(0),
     33       next_in_(nullptr),
     34       width_(0),
     35       height_(0),
     36       bc_index_(0),
     37       pixel_aspect_(0),
     38       global_sort_flag_(0),
     39       global_color_resolution_(0),
     40       img_pass_num_(0) {}
     41 
     42 CFX_GifContext::~CFX_GifContext() {}
     43 
     44 void CFX_GifContext::RecordCurrentPosition(uint32_t* cur_pos) {
     45   delegate_->GifRecordCurrentPosition(*cur_pos);
     46 }
     47 
     48 void CFX_GifContext::ReadScanline(int32_t row_num, uint8_t* row_buf) {
     49   delegate_->GifReadScanline(row_num, row_buf);
     50 }
     51 
     52 bool CFX_GifContext::GetRecordPosition(uint32_t cur_pos,
     53                                        int32_t left,
     54                                        int32_t top,
     55                                        int32_t width,
     56                                        int32_t height,
     57                                        int32_t pal_num,
     58                                        CFX_GifPalette* pal,
     59                                        int32_t delay_time,
     60                                        bool user_input,
     61                                        int32_t trans_index,
     62                                        int32_t disposal_method,
     63                                        bool interlace) {
     64   return delegate_->GifInputRecordPositionBuf(
     65       cur_pos, FX_RECT(left, top, left + width, top + height), pal_num, pal,
     66       delay_time, user_input, trans_index, disposal_method, interlace);
     67 }
     68 
     69 CFX_GifDecodeStatus CFX_GifContext::ReadHeader() {
     70   CFX_GifDecodeStatus status = ReadGifSignature();
     71   if (status != CFX_GifDecodeStatus::Success)
     72     return status;
     73   return ReadLogicalScreenDescriptor();
     74 }
     75 
     76 CFX_GifDecodeStatus CFX_GifContext::GetFrame() {
     77   CFX_GifDecodeStatus ret = CFX_GifDecodeStatus::Success;
     78   while (true) {
     79     switch (decode_status_) {
     80       case GIF_D_STATUS_TAIL:
     81         return CFX_GifDecodeStatus::Success;
     82       case GIF_D_STATUS_SIG: {
     83         uint8_t* signature = nullptr;
     84         if (!ReadData(&signature, 1))
     85           return CFX_GifDecodeStatus::Unfinished;
     86 
     87         switch (*signature) {
     88           case GIF_SIG_EXTENSION:
     89             SaveDecodingStatus(GIF_D_STATUS_EXT);
     90             continue;
     91           case GIF_SIG_IMAGE:
     92             SaveDecodingStatus(GIF_D_STATUS_IMG_INFO);
     93             continue;
     94           case GIF_SIG_TRAILER:
     95             SaveDecodingStatus(GIF_D_STATUS_TAIL);
     96             return CFX_GifDecodeStatus::Success;
     97           default:
     98             if (avail_in_) {
     99               // The Gif File has non_standard Tag!
    100               SaveDecodingStatus(GIF_D_STATUS_SIG);
    101               continue;
    102             }
    103             // The Gif File Doesn't have Trailer Tag!
    104             return CFX_GifDecodeStatus::Success;
    105         }
    106       }
    107       case GIF_D_STATUS_EXT: {
    108         uint8_t* extension = nullptr;
    109         if (!ReadData(&extension, 1))
    110           return CFX_GifDecodeStatus::Unfinished;
    111 
    112         switch (*extension) {
    113           case GIF_BLOCK_CE:
    114             SaveDecodingStatus(GIF_D_STATUS_EXT_CE);
    115             continue;
    116           case GIF_BLOCK_GCE:
    117             SaveDecodingStatus(GIF_D_STATUS_EXT_GCE);
    118             continue;
    119           case GIF_BLOCK_PTE:
    120             SaveDecodingStatus(GIF_D_STATUS_EXT_PTE);
    121             continue;
    122           default: {
    123             int32_t status = GIF_D_STATUS_EXT_UNE;
    124             if (*extension == GIF_BLOCK_PTE) {
    125               status = GIF_D_STATUS_EXT_PTE;
    126             }
    127             SaveDecodingStatus(status);
    128             continue;
    129           }
    130         }
    131       }
    132       case GIF_D_STATUS_IMG_INFO: {
    133         ret = DecodeImageInfo();
    134         if (ret != CFX_GifDecodeStatus::Success)
    135           return ret;
    136 
    137         continue;
    138       }
    139       case GIF_D_STATUS_IMG_DATA: {
    140         uint8_t* img_data_size = nullptr;
    141         uint8_t* img_data = nullptr;
    142         uint32_t skip_size_org = skip_size_;
    143         if (!ReadData(&img_data_size, 1))
    144           return CFX_GifDecodeStatus::Unfinished;
    145 
    146         while (*img_data_size != GIF_BLOCK_TERMINAL) {
    147           if (!ReadData(&img_data, *img_data_size)) {
    148             skip_size_ = skip_size_org;
    149             return CFX_GifDecodeStatus::Unfinished;
    150           }
    151 
    152           SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
    153           skip_size_org = skip_size_;
    154           if (!ReadData(&img_data_size, 1))
    155             return CFX_GifDecodeStatus::Unfinished;
    156         }
    157         SaveDecodingStatus(GIF_D_STATUS_SIG);
    158         continue;
    159       }
    160       default: {
    161         ret = DecodeExtension();
    162         if (ret != CFX_GifDecodeStatus::Success)
    163           return ret;
    164         break;
    165       }
    166     }
    167   }
    168   return CFX_GifDecodeStatus::Success;
    169 }
    170 
    171 CFX_GifDecodeStatus CFX_GifContext::LoadFrame(int32_t frame_num) {
    172   if (!pdfium::IndexInBounds(images_, frame_num))
    173     return CFX_GifDecodeStatus::Error;
    174 
    175   uint8_t* img_data_size = nullptr;
    176   uint8_t* img_data = nullptr;
    177   uint32_t skip_size_org = skip_size_;
    178   CFX_GifImage* gif_image = images_[static_cast<size_t>(frame_num)].get();
    179   if (gif_image->image_info.height == 0)
    180     return CFX_GifDecodeStatus::Error;
    181 
    182   uint32_t gif_img_row_bytes = gif_image->image_info.width;
    183   if (gif_img_row_bytes == 0)
    184     return CFX_GifDecodeStatus::Error;
    185 
    186   if (decode_status_ == GIF_D_STATUS_TAIL) {
    187     gif_image->row_buffer.resize(gif_img_row_bytes);
    188     CFX_GifGraphicControlExtension* gif_img_gce = gif_image->image_GCE.get();
    189     int32_t loc_pal_num =
    190         gif_image->image_info.local_flags.local_pal
    191             ? (2 << gif_image->image_info.local_flags.pal_bits)
    192             : 0;
    193     avail_in_ = 0;
    194     CFX_GifPalette* pLocalPalette = gif_image->local_palettes.empty()
    195                                         ? nullptr
    196                                         : gif_image->local_palettes.data();
    197     if (!gif_img_gce) {
    198       bool bRes = GetRecordPosition(
    199           gif_image->data_pos, gif_image->image_info.left,
    200           gif_image->image_info.top, gif_image->image_info.width,
    201           gif_image->image_info.height, loc_pal_num, pLocalPalette, 0, 0, -1, 0,
    202           gif_image->image_info.local_flags.interlace);
    203       if (!bRes) {
    204         gif_image->row_buffer.clear();
    205         return CFX_GifDecodeStatus::Error;
    206       }
    207     } else {
    208       bool bRes = GetRecordPosition(
    209           gif_image->data_pos, gif_image->image_info.left,
    210           gif_image->image_info.top, gif_image->image_info.width,
    211           gif_image->image_info.height, loc_pal_num, pLocalPalette,
    212           static_cast<int32_t>(gif_image->image_GCE->delay_time),
    213           gif_image->image_GCE->gce_flags.user_input,
    214           gif_image->image_GCE->gce_flags.transparency
    215               ? static_cast<int32_t>(gif_image->image_GCE->trans_index)
    216               : -1,
    217           static_cast<int32_t>(gif_image->image_GCE->gce_flags.disposal_method),
    218           gif_image->image_info.local_flags.interlace);
    219       if (!bRes) {
    220         gif_image->row_buffer.clear();
    221         return CFX_GifDecodeStatus::Error;
    222       }
    223     }
    224 
    225     if (gif_image->code_exp > GIF_MAX_LZW_EXP) {
    226       gif_image->row_buffer.clear();
    227       return CFX_GifDecodeStatus::Error;
    228     }
    229 
    230     img_row_offset_ = 0;
    231     img_row_avail_size_ = 0;
    232     img_pass_num_ = 0;
    233     gif_image->row_num = 0;
    234     SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
    235   }
    236 
    237   if (decode_status_ == GIF_D_STATUS_IMG_DATA) {
    238     if (!ReadData(&img_data_size, 1))
    239       return CFX_GifDecodeStatus::Unfinished;
    240 
    241     if (*img_data_size != GIF_BLOCK_TERMINAL) {
    242       if (!ReadData(&img_data, *img_data_size)) {
    243         skip_size_ = skip_size_org;
    244         return CFX_GifDecodeStatus::Unfinished;
    245       }
    246 
    247       if (!lzw_decompressor_.get())
    248         lzw_decompressor_ = CFX_LZWDecompressor::Create(
    249             !gif_image->local_palettes.empty() ? gif_image->local_pallette_exp
    250                                                : global_pal_exp_,
    251             gif_image->code_exp);
    252       SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
    253       img_row_offset_ += img_row_avail_size_;
    254       img_row_avail_size_ = gif_img_row_bytes - img_row_offset_;
    255       CFX_GifDecodeStatus ret =
    256           lzw_decompressor_.get()
    257               ? lzw_decompressor_->Decode(
    258                     img_data, *img_data_size,
    259                     gif_image->row_buffer.data() + img_row_offset_,
    260                     &img_row_avail_size_)
    261               : CFX_GifDecodeStatus::Error;
    262       if (ret == CFX_GifDecodeStatus::Error) {
    263         DecodingFailureAtTailCleanup(gif_image);
    264         return CFX_GifDecodeStatus::Error;
    265       }
    266       while (ret != CFX_GifDecodeStatus::Error) {
    267         if (ret == CFX_GifDecodeStatus::Success) {
    268           ReadScanline(gif_image->row_num, gif_image->row_buffer.data());
    269           gif_image->row_buffer.clear();
    270           SaveDecodingStatus(GIF_D_STATUS_TAIL);
    271           return CFX_GifDecodeStatus::Success;
    272         }
    273         if (ret == CFX_GifDecodeStatus::Unfinished) {
    274           skip_size_org = skip_size_;
    275           if (!ReadData(&img_data_size, 1))
    276             return CFX_GifDecodeStatus::Unfinished;
    277 
    278           if (*img_data_size != GIF_BLOCK_TERMINAL) {
    279             if (!ReadData(&img_data, *img_data_size)) {
    280               skip_size_ = skip_size_org;
    281               return CFX_GifDecodeStatus::Unfinished;
    282             }
    283             if (!lzw_decompressor_.get())
    284               lzw_decompressor_ = CFX_LZWDecompressor::Create(
    285                   !gif_image->local_palettes.empty()
    286                       ? gif_image->local_pallette_exp
    287                       : global_pal_exp_,
    288                   gif_image->code_exp);
    289             SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
    290             img_row_offset_ += img_row_avail_size_;
    291             img_row_avail_size_ = gif_img_row_bytes - img_row_offset_;
    292             ret = lzw_decompressor_.get()
    293                       ? lzw_decompressor_->Decode(
    294                             img_data, *img_data_size,
    295                             gif_image->row_buffer.data() + img_row_offset_,
    296                             &img_row_avail_size_)
    297                       : CFX_GifDecodeStatus::Error;
    298           }
    299         }
    300         if (ret == CFX_GifDecodeStatus::InsufficientDestSize) {
    301           if (gif_image->image_info.local_flags.interlace) {
    302             ReadScanline(gif_image->row_num, gif_image->row_buffer.data());
    303             gif_image->row_num += s_gif_interlace_step[img_pass_num_];
    304             if (gif_image->row_num >=
    305                 static_cast<int32_t>(gif_image->image_info.height)) {
    306               img_pass_num_++;
    307               if (img_pass_num_ == FX_ArraySize(s_gif_interlace_step)) {
    308                 DecodingFailureAtTailCleanup(gif_image);
    309                 return CFX_GifDecodeStatus::Error;
    310               }
    311               gif_image->row_num = s_gif_interlace_step[img_pass_num_] / 2;
    312             }
    313           } else {
    314             ReadScanline(gif_image->row_num++, gif_image->row_buffer.data());
    315           }
    316           img_row_offset_ = 0;
    317           img_row_avail_size_ = gif_img_row_bytes;
    318           ret = lzw_decompressor_.get()
    319                     ? lzw_decompressor_->Decode(
    320                           img_data, *img_data_size,
    321                           gif_image->row_buffer.data() + img_row_offset_,
    322                           &img_row_avail_size_)
    323                     : CFX_GifDecodeStatus::Error;
    324         }
    325         if (ret == CFX_GifDecodeStatus::Error) {
    326           DecodingFailureAtTailCleanup(gif_image);
    327           return CFX_GifDecodeStatus::Error;
    328         }
    329       }
    330     }
    331     SaveDecodingStatus(GIF_D_STATUS_TAIL);
    332   }
    333   return CFX_GifDecodeStatus::Error;
    334 }
    335 
    336 void CFX_GifContext::SetInputBuffer(uint8_t* src_buf, uint32_t src_size) {
    337   next_in_ = src_buf;
    338   avail_in_ = src_size;
    339   skip_size_ = 0;
    340 }
    341 
    342 uint32_t CFX_GifContext::GetAvailInput(uint8_t** avail_buf) const {
    343   if (avail_buf) {
    344     *avail_buf = nullptr;
    345     if (avail_in_ > 0)
    346       *avail_buf = next_in_;
    347   }
    348   return avail_in_;
    349 }
    350 
    351 uint8_t* CFX_GifContext::ReadData(uint8_t** des_buf_pp, uint32_t data_size) {
    352   if (!next_in_)
    353     return nullptr;
    354   if (avail_in_ <= skip_size_)
    355     return nullptr;
    356   if (!des_buf_pp)
    357     return nullptr;
    358   if (data_size == 0)
    359     return nullptr;
    360   if (avail_in_ - skip_size_ < data_size)
    361     return nullptr;
    362 
    363   *des_buf_pp = next_in_ + skip_size_;
    364   skip_size_ += data_size;
    365   return *des_buf_pp;
    366 }
    367 
    368 CFX_GifDecodeStatus CFX_GifContext::ReadGifSignature() {
    369   CFX_GifHeader* header = nullptr;
    370   uint32_t skip_size_org = skip_size_;
    371   if (!ReadData(reinterpret_cast<uint8_t**>(&header), 6)) {
    372     skip_size_ = skip_size_org;
    373     return CFX_GifDecodeStatus::Unfinished;
    374   }
    375 
    376   if (strncmp(header->signature, kGifSignature87, 6) != 0 &&
    377       strncmp(header->signature, kGifSignature89, 6) != 0)
    378     return CFX_GifDecodeStatus::Error;
    379 
    380   return CFX_GifDecodeStatus::Success;
    381 }
    382 
    383 CFX_GifDecodeStatus CFX_GifContext::ReadLogicalScreenDescriptor() {
    384   CFX_GifLocalScreenDescriptor* lsd = nullptr;
    385   uint32_t skip_size_org = skip_size_;
    386   if (!ReadData(reinterpret_cast<uint8_t**>(&lsd), 7)) {
    387     skip_size_ = skip_size_org;
    388     return CFX_GifDecodeStatus::Unfinished;
    389   }
    390 
    391   if (lsd->global_flags.global_pal) {
    392     uint32_t palette_count = unsigned(2 << lsd->global_flags.pal_bits);
    393     if (lsd->bc_index >= palette_count)
    394       return CFX_GifDecodeStatus::Error;
    395     bc_index_ = lsd->bc_index;
    396 
    397     uint32_t palette_size = palette_count * 3u;
    398     uint8_t* palette = nullptr;
    399     if (!ReadData(&palette, palette_size)) {
    400       skip_size_ = skip_size_org;
    401       return CFX_GifDecodeStatus::Unfinished;
    402     }
    403 
    404     global_pal_exp_ = lsd->global_flags.pal_bits;
    405     global_sort_flag_ = lsd->global_flags.sort_flag;
    406     global_color_resolution_ = lsd->global_flags.color_resolution;
    407     global_palette_.resize(palette_count);
    408     memcpy(global_palette_.data(), palette, palette_size);
    409   }
    410 
    411   width_ = static_cast<int>(
    412       FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&lsd->width)));
    413   height_ = static_cast<int>(
    414       FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&lsd->height)));
    415 
    416   pixel_aspect_ = lsd->pixel_aspect;
    417   return CFX_GifDecodeStatus::Success;
    418 }
    419 
    420 void CFX_GifContext::SaveDecodingStatus(int32_t status) {
    421   decode_status_ = status;
    422   next_in_ += skip_size_;
    423   avail_in_ -= skip_size_;
    424   skip_size_ = 0;
    425 }
    426 
    427 CFX_GifDecodeStatus CFX_GifContext::DecodeExtension() {
    428   uint8_t* data_size = nullptr;
    429   uint8_t* data_buf = nullptr;
    430   uint32_t skip_size_org = skip_size_;
    431   switch (decode_status_) {
    432     case GIF_D_STATUS_EXT_CE: {
    433       if (!ReadData(&data_size, 1)) {
    434         skip_size_ = skip_size_org;
    435         return CFX_GifDecodeStatus::Unfinished;
    436       }
    437 
    438       cmt_data_.clear();
    439       while (*data_size != GIF_BLOCK_TERMINAL) {
    440         uint8_t block_size = *data_size;
    441         if (!ReadData(&data_buf, *data_size) || !ReadData(&data_size, 1)) {
    442           skip_size_ = skip_size_org;
    443           return CFX_GifDecodeStatus::Unfinished;
    444         }
    445 
    446         cmt_data_ += ByteString(data_buf, block_size);
    447       }
    448       break;
    449     }
    450     case GIF_D_STATUS_EXT_PTE: {
    451       CFX_GifPlainTextExtension* gif_pte = nullptr;
    452       if (!ReadData(reinterpret_cast<uint8_t**>(&gif_pte), 13))
    453         return CFX_GifDecodeStatus::Unfinished;
    454 
    455       graphic_control_extension_ = nullptr;
    456       if (!ReadData(&data_size, 1)) {
    457         skip_size_ = skip_size_org;
    458         return CFX_GifDecodeStatus::Unfinished;
    459       }
    460 
    461       while (*data_size != GIF_BLOCK_TERMINAL) {
    462         if (!ReadData(&data_buf, *data_size) || !ReadData(&data_size, 1)) {
    463           skip_size_ = skip_size_org;
    464           return CFX_GifDecodeStatus::Unfinished;
    465         }
    466       }
    467       break;
    468     }
    469     case GIF_D_STATUS_EXT_GCE: {
    470       CFX_GifGraphicControlExtension* gif_gce = nullptr;
    471       if (!ReadData(reinterpret_cast<uint8_t**>(&gif_gce), 6))
    472         return CFX_GifDecodeStatus::Unfinished;
    473 
    474       if (!graphic_control_extension_.get())
    475         graphic_control_extension_ =
    476             pdfium::MakeUnique<CFX_GifGraphicControlExtension>();
    477       graphic_control_extension_->block_size = gif_gce->block_size;
    478       graphic_control_extension_->gce_flags = gif_gce->gce_flags;
    479       graphic_control_extension_->delay_time =
    480           FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&gif_gce->delay_time));
    481       graphic_control_extension_->trans_index = gif_gce->trans_index;
    482       break;
    483     }
    484     default: {
    485       if (decode_status_ == GIF_D_STATUS_EXT_PTE)
    486         graphic_control_extension_ = nullptr;
    487       if (!ReadData(&data_size, 1))
    488         return CFX_GifDecodeStatus::Unfinished;
    489 
    490       while (*data_size != GIF_BLOCK_TERMINAL) {
    491         if (!ReadData(&data_buf, *data_size) || !ReadData(&data_size, 1)) {
    492           skip_size_ = skip_size_org;
    493           return CFX_GifDecodeStatus::Unfinished;
    494         }
    495       }
    496     }
    497   }
    498   SaveDecodingStatus(GIF_D_STATUS_SIG);
    499   return CFX_GifDecodeStatus::Success;
    500 }
    501 
    502 CFX_GifDecodeStatus CFX_GifContext::DecodeImageInfo() {
    503   if (width_ <= 0 || height_ <= 0)
    504     return CFX_GifDecodeStatus::Error;
    505 
    506   uint32_t skip_size_org = skip_size_;
    507   CFX_CFX_GifImageInfo* img_info = nullptr;
    508   if (!ReadData(reinterpret_cast<uint8_t**>(&img_info), 9))
    509     return CFX_GifDecodeStatus::Unfinished;
    510 
    511   auto gif_image = pdfium::MakeUnique<CFX_GifImage>();
    512   gif_image->image_info.left =
    513       FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&img_info->left));
    514   gif_image->image_info.top =
    515       FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&img_info->top));
    516   gif_image->image_info.width =
    517       FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&img_info->width));
    518   gif_image->image_info.height =
    519       FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&img_info->height));
    520   gif_image->image_info.local_flags = img_info->local_flags;
    521   if (gif_image->image_info.left + gif_image->image_info.width > width_ ||
    522       gif_image->image_info.top + gif_image->image_info.height > height_)
    523     return CFX_GifDecodeStatus::Error;
    524 
    525   CFX_GifLocalFlags* gif_img_info_lf = &img_info->local_flags;
    526   if (gif_img_info_lf->local_pal) {
    527     gif_image->local_pallette_exp = gif_img_info_lf->pal_bits;
    528     uint32_t loc_pal_size = unsigned(2 << gif_img_info_lf->pal_bits) * 3u;
    529     uint8_t* loc_pal = nullptr;
    530     if (!ReadData(&loc_pal, loc_pal_size)) {
    531       skip_size_ = skip_size_org;
    532       return CFX_GifDecodeStatus::Unfinished;
    533     }
    534 
    535     gif_image->local_palettes = std::vector<CFX_GifPalette>(loc_pal_size / 3);
    536     std::copy(loc_pal, loc_pal + loc_pal_size,
    537               reinterpret_cast<uint8_t*>(gif_image->local_palettes.data()));
    538   }
    539 
    540   uint8_t* code_size = nullptr;
    541   if (!ReadData(&code_size, 1)) {
    542     skip_size_ = skip_size_org;
    543     return CFX_GifDecodeStatus::Unfinished;
    544   }
    545 
    546   gif_image->code_exp = *code_size;
    547   RecordCurrentPosition(&gif_image->data_pos);
    548   gif_image->data_pos += skip_size_;
    549   gif_image->image_GCE = nullptr;
    550   if (graphic_control_extension_.get()) {
    551     if (graphic_control_extension_->gce_flags.transparency) {
    552       // Need to test that the color that is going to be transparent is actually
    553       // in the palette being used.
    554       if (graphic_control_extension_->trans_index >=
    555           2 << (gif_image->local_palettes.empty()
    556                     ? global_pal_exp_
    557                     : gif_image->local_pallette_exp))
    558         return CFX_GifDecodeStatus::Error;
    559     }
    560     gif_image->image_GCE = std::move(graphic_control_extension_);
    561     graphic_control_extension_ = nullptr;
    562   }
    563 
    564   images_.push_back(std::move(gif_image));
    565   SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
    566   return CFX_GifDecodeStatus::Success;
    567 }
    568 
    569 void CFX_GifContext::DecodingFailureAtTailCleanup(CFX_GifImage* gif_image) {
    570   gif_image->row_buffer.clear();
    571   SaveDecodingStatus(GIF_D_STATUS_TAIL);
    572 }
    573