tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsGIFDecoder2.cpp (42497B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 *
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 /*
      7 The Graphics Interchange Format(c) is the copyright property of CompuServe
      8 Incorporated. Only CompuServe Incorporated is authorized to define, redefine,
      9 enhance, alter, modify or change in any way the definition of the format.
     10 
     11 CompuServe Incorporated hereby grants a limited, non-exclusive, royalty-free
     12 license for the use of the Graphics Interchange Format(sm) in computer
     13 software; computer software utilizing GIF(sm) must acknowledge ownership of the
     14 Graphics Interchange Format and its Service Mark by CompuServe Incorporated, in
     15 User and Technical Documentation. Computer software utilizing GIF, which is
     16 distributed or may be distributed without User or Technical Documentation must
     17 display to the screen or printer a message acknowledging ownership of the
     18 Graphics Interchange Format and the Service Mark by CompuServe Incorporated; in
     19 this case, the acknowledgement may be displayed in an opening screen or leading
     20 banner, or a closing screen or trailing banner. A message such as the following
     21 may be used:
     22 
     23    "The Graphics Interchange Format(c) is the Copyright property of
     24    CompuServe Incorporated. GIF(sm) is a Service Mark property of
     25    CompuServe Incorporated."
     26 
     27 For further information, please contact :
     28 
     29    CompuServe Incorporated
     30    Graphics Technology Department
     31    5000 Arlington Center Boulevard
     32    Columbus, Ohio  43220
     33    U. S. A.
     34 
     35 CompuServe Incorporated maintains a mailing list with all those individuals and
     36 organizations who wish to receive copies of this document when it is corrected
     37 or revised. This service is offered free of charge; please provide us with your
     38 mailing address.
     39 */
     40 
     41 #include "nsGIFDecoder2.h"
     42 
     43 #include <stddef.h>
     44 
     45 #include "imgFrame.h"
     46 #include "mozilla/EndianUtils.h"
     47 #include "RasterImage.h"
     48 #include "SurfacePipeFactory.h"
     49 
     50 #include "gfxColor.h"
     51 #include "gfxPlatform.h"
     52 #include "qcms.h"
     53 #include <algorithm>
     54 
     55 using namespace mozilla::gfx;
     56 
     57 using std::max;
     58 
     59 namespace mozilla {
     60 namespace image {
     61 
     62 //////////////////////////////////////////////////////////////////////
     63 // GIF Decoder Implementation
     64 
     65 static const size_t GIF_HEADER_LEN = 6;
     66 static const size_t GIF_SCREEN_DESCRIPTOR_LEN = 7;
     67 static const size_t BLOCK_HEADER_LEN = 1;
     68 static const size_t SUB_BLOCK_HEADER_LEN = 1;
     69 static const size_t EXTENSION_HEADER_LEN = 2;
     70 static const size_t GRAPHIC_CONTROL_EXTENSION_LEN = 4;
     71 static const size_t APPLICATION_EXTENSION_LEN = 11;
     72 static const size_t IMAGE_DESCRIPTOR_LEN = 9;
     73 
     74 // Masks for reading color table information from packed fields in the screen
     75 // descriptor and image descriptor blocks.
     76 static const uint8_t PACKED_FIELDS_COLOR_TABLE_BIT = 0x80;
     77 static const uint8_t PACKED_FIELDS_INTERLACED_BIT = 0x40;
     78 static const uint8_t PACKED_FIELDS_TABLE_DEPTH_MASK = 0x07;
     79 
     80 nsGIFDecoder2::nsGIFDecoder2(RasterImage* aImage)
     81    : Decoder(aImage),
     82      mLexer(Transition::To(State::GIF_HEADER, GIF_HEADER_LEN),
     83             Transition::TerminateSuccess()),
     84      mOldColor(0),
     85      mCurrentFrameIndex(-1),
     86      mColorTablePos(0),
     87      mColormap(nullptr),
     88      mColormapSize(0),
     89      mColorMask('\0'),
     90      mGIFOpen(false),
     91      mSawTransparency(false),
     92      mSwizzleFn(nullptr) {
     93  // Clear out the structure, excluding the arrays. Ensure that the global
     94  // colormap is initialized as opaque.
     95  memset(&mGIFStruct, 0, sizeof(mGIFStruct));
     96  memset(mGIFStruct.global_colormap, 0xFF, sizeof(mGIFStruct.global_colormap));
     97 
     98  // Each color table will need to be unpacked.
     99  mSwizzleFn = SwizzleRow(SurfaceFormat::R8G8B8, SurfaceFormat::OS_RGBA);
    100  MOZ_ASSERT(mSwizzleFn);
    101 }
    102 
    103 nsGIFDecoder2::~nsGIFDecoder2() { free(mGIFStruct.local_colormap); }
    104 
    105 nsresult nsGIFDecoder2::FinishWithErrorInternal() {
    106  if (mGIFOpen) {
    107    if (WantsFrameCount()) {
    108      PostFrameCount(mGIFStruct.images_decoded);
    109    }
    110    PostLoopCount(mGIFStruct.loop_count);
    111    mGIFOpen = false;
    112  }
    113 
    114  return Decoder::FinishWithErrorInternal();
    115 }
    116 
    117 nsresult nsGIFDecoder2::FinishInternal() {
    118  MOZ_ASSERT(!HasError(), "Shouldn't call FinishInternal after error!");
    119 
    120  if (!mGIFOpen) {
    121    return NS_OK;
    122  }
    123 
    124  PostLoopCount(mGIFStruct.loop_count);
    125 
    126  // If the GIF got cut off, handle it anyway
    127  if (mCurrentFrameIndex == mGIFStruct.images_decoded) {
    128    EndImageFrame();
    129  }
    130 
    131  if (WantsFrameCount()) {
    132    PostFrameCount(mGIFStruct.images_decoded);
    133  }
    134 
    135  if (!IsMetadataDecode()) {
    136    PostDecodeDone();
    137  }
    138 
    139  mGIFOpen = false;
    140  return NS_OK;
    141 }
    142 
    143 void nsGIFDecoder2::FlushImageData() {
    144  Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
    145  if (!invalidRect) {
    146    return;
    147  }
    148 
    149  PostInvalidation(invalidRect->mInputSpaceRect,
    150                   Some(invalidRect->mOutputSpaceRect));
    151 }
    152 
    153 //******************************************************************************
    154 // GIF decoder callback methods. Part of public API for GIF2
    155 //******************************************************************************
    156 
    157 //******************************************************************************
    158 void nsGIFDecoder2::BeginGIF() {
    159  if (mGIFOpen) {
    160    return;
    161  }
    162 
    163  mGIFOpen = true;
    164 
    165  PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
    166 }
    167 
    168 bool nsGIFDecoder2::CheckForTransparency(const OrientedIntRect& aFrameRect) {
    169  // Check if the image has a transparent color in its palette.
    170  if (mGIFStruct.is_transparent) {
    171    PostHasTransparency();
    172    return true;
    173  }
    174 
    175  // This is a bit of a hack. Some sites will use a 1x1 gif that includes no
    176  // header information indicating it is transparent, no palette, and no image
    177  // data at all (so no pixels get written) to represent a transparent pixel
    178  // using the absolute least number of bytes. Generally things are setup to
    179  // detect transparency without decoding the image data. So to detect this kind
    180  // of transparency without decoing the image data we would have to assume
    181  // every gif is transparent, which we would like to avoid. Changing things so
    182  // that we can detect transparency at any point of decoding is a bigger change
    183  // and not worth it for one questionable 1x1 gif. Using this "trick" for
    184  // anything but 1x1 transparent spacer gifs doesn't make sense, so it's
    185  // reasonable to target 1x1 gifs just for this.
    186  if (mGIFStruct.screen_width == 1 && mGIFStruct.screen_height == 1) {
    187    PostHasTransparency();
    188    return true;
    189  }
    190 
    191  if (mGIFStruct.images_decoded > 0) {
    192    return false;  // We only care about first frame padding below.
    193  }
    194 
    195  // If we need padding on the first frame, that means we don't draw into part
    196  // of the image at all. Report that as transparency.
    197  OrientedIntRect imageRect(0, 0, mGIFStruct.screen_width,
    198                            mGIFStruct.screen_height);
    199  if (!imageRect.IsEqualEdges(aFrameRect)) {
    200    PostHasTransparency();
    201    mSawTransparency = true;  // Make sure we don't optimize it away.
    202    return true;
    203  }
    204 
    205  return false;
    206 }
    207 
    208 //******************************************************************************
    209 nsresult nsGIFDecoder2::BeginImageFrame(const OrientedIntRect& aFrameRect,
    210                                        uint16_t aDepth, bool aIsInterlaced) {
    211  MOZ_ASSERT(HasSize());
    212 
    213  // If we are just counting frames for a metadata decode, there is no actual
    214  // decoding done. We are just iterating over the blocks to find when a frame
    215  // begins and ends.
    216  if (WantsFrameCount()) {
    217    mCurrentFrameIndex = mGIFStruct.images_decoded;
    218    return NS_OK;
    219  }
    220 
    221  bool hasTransparency = CheckForTransparency(aFrameRect);
    222 
    223  // Make sure there's no animation if we're downscaling.
    224  MOZ_ASSERT_IF(Size() != OutputSize(), !GetImageMetadata().HasAnimation());
    225 
    226  Maybe<AnimationParams> animParams;
    227  if (!IsFirstFrameDecode()) {
    228    animParams.emplace(aFrameRect.ToUnknownRect(),
    229                       FrameTimeout::FromRawMilliseconds(mGIFStruct.delay_time),
    230                       uint32_t(mGIFStruct.images_decoded), BlendMethod::OVER,
    231                       DisposalMethod(mGIFStruct.disposal_method));
    232  }
    233 
    234  SurfacePipeFlags pipeFlags =
    235      aIsInterlaced ? SurfacePipeFlags::DEINTERLACE : SurfacePipeFlags();
    236 
    237  gfx::SurfaceFormat format;
    238  if (mGIFStruct.images_decoded == 0) {
    239    // The first frame may be displayed progressively.
    240    pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY;
    241 
    242    // Only allow opaque surfaces if we are decoding a single image without
    243    // transparency. For an animation, there isn't much benefit to RGBX given
    244    // the current frame is constantly changing, and there are many risks
    245    // since BlendAnimationFilter is able to clear rows of data.
    246    format = hasTransparency || animParams ? SurfaceFormat::OS_RGBA
    247                                           : SurfaceFormat::OS_RGBX;
    248  } else {
    249    format = SurfaceFormat::OS_RGBA;
    250  }
    251 
    252  Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
    253      this, Size(), OutputSize(), aFrameRect, format, format, animParams,
    254      mTransform, pipeFlags);
    255  mCurrentFrameIndex = mGIFStruct.images_decoded;
    256 
    257  if (!pipe) {
    258    mPipe = SurfacePipe();
    259    return NS_ERROR_FAILURE;
    260  }
    261 
    262  mPipe = std::move(*pipe);
    263  return NS_OK;
    264 }
    265 
    266 //******************************************************************************
    267 void nsGIFDecoder2::EndImageFrame() {
    268  if (WantsFrameCount()) {
    269    mGIFStruct.pixels_remaining = 0;
    270    mGIFStruct.images_decoded++;
    271    mGIFStruct.delay_time = 0;
    272    mColormap = nullptr;
    273    mColormapSize = 0;
    274    mCurrentFrameIndex = -1;
    275 
    276    // Keep updating the count every time we find a frame.
    277    PostFrameCount(mGIFStruct.images_decoded);
    278    return;
    279  }
    280 
    281  Opacity opacity = Opacity::SOME_TRANSPARENCY;
    282 
    283  if (mGIFStruct.images_decoded == 0) {
    284    // We need to send invalidations for the first frame.
    285    FlushImageData();
    286 
    287    // The first frame was preallocated with alpha; if it wasn't transparent, we
    288    // should fix that. We can also mark it opaque unconditionally if we didn't
    289    // actually see any transparent pixels - this test is only valid for the
    290    // first frame.
    291    if (!mGIFStruct.is_transparent && !mSawTransparency) {
    292      opacity = Opacity::FULLY_OPAQUE;
    293    }
    294  }
    295 
    296  // Unconditionally increment images_decoded, because we unconditionally
    297  // append frames in BeginImageFrame(). This ensures that images_decoded
    298  // always refers to the frame in mImage we're currently decoding,
    299  // even if some of them weren't decoded properly and thus are blank.
    300  mGIFStruct.images_decoded++;
    301 
    302  // Tell the superclass we finished a frame
    303  PostFrameStop(opacity);
    304 
    305  // Reset the transparent pixel
    306  if (mOldColor) {
    307    mColormap[mGIFStruct.tpixel] = mOldColor;
    308    mOldColor = 0;
    309  }
    310 
    311  // Reset graphic control extension parameters that we shouldn't reuse
    312  // between frames.
    313  mGIFStruct.delay_time = 0;
    314  mGIFStruct.is_transparent = 0;
    315  mGIFStruct.tpixel = 0;
    316  mGIFStruct.disposal_method = 0;
    317 
    318  mColormap = nullptr;
    319  mColormapSize = 0;
    320  mCurrentFrameIndex = -1;
    321 }
    322 
    323 template <typename PixelSize>
    324 PixelSize nsGIFDecoder2::ColormapIndexToPixel(uint8_t aIndex) {
    325  MOZ_ASSERT(sizeof(PixelSize) == sizeof(uint32_t));
    326 
    327  // Retrieve the next color, clamping to the size of the colormap.
    328  uint32_t color = mColormap[aIndex & mColorMask];
    329 
    330  // Check for transparency.
    331  if (mGIFStruct.is_transparent) {
    332    mSawTransparency = mSawTransparency || color == 0;
    333  }
    334 
    335  return color;
    336 }
    337 
    338 template <>
    339 uint8_t nsGIFDecoder2::ColormapIndexToPixel<uint8_t>(uint8_t aIndex) {
    340  return aIndex & mColorMask;
    341 }
    342 
    343 template <typename PixelSize>
    344 std::tuple<int32_t, Maybe<WriteState>> nsGIFDecoder2::YieldPixels(
    345    const uint8_t* aData, size_t aLength, size_t* aBytesReadOut,
    346    PixelSize* aPixelBlock, int32_t aBlockSize) {
    347  MOZ_ASSERT(aData);
    348  MOZ_ASSERT(aBytesReadOut);
    349  MOZ_ASSERT(mGIFStruct.stackp >= mGIFStruct.stack);
    350 
    351  // Advance to the next byte we should read.
    352  const uint8_t* data = aData + *aBytesReadOut;
    353 
    354  int32_t written = 0;
    355  while (aBlockSize > written) {
    356    // If we don't have any decoded data to yield, try to read some input and
    357    // produce some.
    358    if (mGIFStruct.stackp == mGIFStruct.stack) {
    359      while (mGIFStruct.bits < mGIFStruct.codesize &&
    360             *aBytesReadOut < aLength) {
    361        // Feed the next byte into the decoder's 32-bit input buffer.
    362        mGIFStruct.datum += int32_t(*data) << mGIFStruct.bits;
    363        mGIFStruct.bits += 8;
    364        data += 1;
    365        *aBytesReadOut += 1;
    366      }
    367 
    368      if (mGIFStruct.bits < mGIFStruct.codesize) {
    369        return std::make_tuple(written, Some(WriteState::NEED_MORE_DATA));
    370      }
    371 
    372      // Get the leading variable-length symbol from the data stream.
    373      int code = mGIFStruct.datum & mGIFStruct.codemask;
    374      mGIFStruct.datum >>= mGIFStruct.codesize;
    375      mGIFStruct.bits -= mGIFStruct.codesize;
    376 
    377      const int clearCode = ClearCode();
    378 
    379      // Reset the dictionary to its original state, if requested
    380      if (code == clearCode) {
    381        mGIFStruct.codesize = mGIFStruct.datasize + 1;
    382        mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
    383        mGIFStruct.avail = clearCode + 2;
    384        mGIFStruct.oldcode = -1;
    385        return std::make_tuple(written, Some(WriteState::NEED_MORE_DATA));
    386      }
    387 
    388      // Check for explicit end-of-stream code. It should only appear after all
    389      // image data, but if that was the case we wouldn't be in this function,
    390      // so this is always an error condition.
    391      if (code == (clearCode + 1)) {
    392        return std::make_tuple(written, Some(WriteState::FAILURE));
    393      }
    394 
    395      if (mGIFStruct.oldcode == -1) {
    396        if (code >= MAX_BITS) {
    397          // The code's too big; something's wrong.
    398          return std::make_tuple(written, Some(WriteState::FAILURE));
    399        }
    400 
    401        mGIFStruct.firstchar = mGIFStruct.oldcode = code;
    402 
    403        // Yield a pixel at the appropriate index in the colormap.
    404        mGIFStruct.pixels_remaining--;
    405        aPixelBlock[written++] =
    406            ColormapIndexToPixel<PixelSize>(mGIFStruct.suffix[code]);
    407        continue;
    408      }
    409 
    410      int incode = code;
    411      if (code >= mGIFStruct.avail) {
    412        *mGIFStruct.stackp++ = mGIFStruct.firstchar;
    413        code = mGIFStruct.oldcode;
    414 
    415        if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
    416          // Stack overflow; something's wrong.
    417          return std::make_tuple(written, Some(WriteState::FAILURE));
    418        }
    419      }
    420 
    421      while (code >= clearCode) {
    422        if ((code >= MAX_BITS) || (code == mGIFStruct.prefix[code])) {
    423          return std::make_tuple(written, Some(WriteState::FAILURE));
    424        }
    425 
    426        *mGIFStruct.stackp++ = mGIFStruct.suffix[code];
    427        code = mGIFStruct.prefix[code];
    428 
    429        if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
    430          // Stack overflow; something's wrong.
    431          return std::make_tuple(written, Some(WriteState::FAILURE));
    432        }
    433      }
    434 
    435      *mGIFStruct.stackp++ = mGIFStruct.firstchar = mGIFStruct.suffix[code];
    436 
    437      // Define a new codeword in the dictionary.
    438      if (mGIFStruct.avail < 4096) {
    439        mGIFStruct.prefix[mGIFStruct.avail] = mGIFStruct.oldcode;
    440        mGIFStruct.suffix[mGIFStruct.avail] = mGIFStruct.firstchar;
    441        mGIFStruct.avail++;
    442 
    443        // If we've used up all the codewords of a given length increase the
    444        // length of codewords by one bit, but don't exceed the specified
    445        // maximum codeword size of 12 bits.
    446        if (((mGIFStruct.avail & mGIFStruct.codemask) == 0) &&
    447            (mGIFStruct.avail < 4096)) {
    448          mGIFStruct.codesize++;
    449          mGIFStruct.codemask += mGIFStruct.avail;
    450        }
    451      }
    452 
    453      mGIFStruct.oldcode = incode;
    454    }
    455 
    456    if (MOZ_UNLIKELY(mGIFStruct.stackp <= mGIFStruct.stack)) {
    457      MOZ_ASSERT_UNREACHABLE("No decoded data but we didn't return early?");
    458      return std::make_tuple(written, Some(WriteState::FAILURE));
    459    }
    460 
    461    // Yield a pixel at the appropriate index in the colormap.
    462    mGIFStruct.pixels_remaining--;
    463    aPixelBlock[written++] =
    464        ColormapIndexToPixel<PixelSize>(*--mGIFStruct.stackp);
    465  }
    466 
    467  return std::make_tuple(written, Maybe<WriteState>());
    468 }
    469 
    470 /// Expand the colormap from RGB to Packed ARGB as needed by Cairo.
    471 /// And apply any LCMS transformation.
    472 void nsGIFDecoder2::ConvertColormap(uint32_t* aColormap, uint32_t aColors) {
    473  // If we are just counting frames for a metadata decode, there is no need to
    474  // prep the colormap.
    475  if (!aColors || WantsFrameCount()) {
    476    return;
    477  }
    478 
    479  // Apply CMS transformation if enabled and available
    480  if (mCMSMode == CMSMode::All) {
    481    qcms_transform* transform = GetCMSsRGBTransform(SurfaceFormat::R8G8B8);
    482    if (transform) {
    483      qcms_transform_data(transform, aColormap, aColormap, aColors);
    484    }
    485  }
    486 
    487  // Expand color table from RGB to BGRA.
    488  MOZ_ASSERT(mSwizzleFn);
    489  uint8_t* data = reinterpret_cast<uint8_t*>(aColormap);
    490  mSwizzleFn(data, data, aColors);
    491 }
    492 
    493 LexerResult nsGIFDecoder2::DoDecode(SourceBufferIterator& aIterator,
    494                                    IResumable* aOnResume) {
    495  MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
    496 
    497  return mLexer.Lex(
    498      aIterator, aOnResume,
    499      [=](State aState, const char* aData, size_t aLength) {
    500        switch (aState) {
    501          case State::GIF_HEADER:
    502            return ReadGIFHeader(aData);
    503          case State::SCREEN_DESCRIPTOR:
    504            return ReadScreenDescriptor(aData);
    505          case State::GLOBAL_COLOR_TABLE:
    506            return ReadGlobalColorTable(aData, aLength);
    507          case State::FINISHED_GLOBAL_COLOR_TABLE:
    508            return FinishedGlobalColorTable();
    509          case State::BLOCK_HEADER:
    510            return ReadBlockHeader(aData);
    511          case State::EXTENSION_HEADER:
    512            return ReadExtensionHeader(aData);
    513          case State::GRAPHIC_CONTROL_EXTENSION:
    514            return ReadGraphicControlExtension(aData);
    515          case State::APPLICATION_IDENTIFIER:
    516            return ReadApplicationIdentifier(aData);
    517          case State::NETSCAPE_EXTENSION_SUB_BLOCK:
    518            return ReadNetscapeExtensionSubBlock(aData);
    519          case State::NETSCAPE_EXTENSION_DATA:
    520            return ReadNetscapeExtensionData(aData);
    521          case State::IMAGE_DESCRIPTOR:
    522            return ReadImageDescriptor(aData);
    523          case State::LOCAL_COLOR_TABLE:
    524            return ReadLocalColorTable(aData, aLength);
    525          case State::FINISHED_LOCAL_COLOR_TABLE:
    526            return FinishedLocalColorTable();
    527          case State::IMAGE_DATA_BLOCK:
    528            return ReadImageDataBlock(aData);
    529          case State::IMAGE_DATA_SUB_BLOCK:
    530            return ReadImageDataSubBlock(aData);
    531          case State::LZW_DATA:
    532            return ReadLZWData(aData, aLength);
    533          case State::SKIP_LZW_DATA:
    534            return Transition::ContinueUnbuffered(State::SKIP_LZW_DATA);
    535          case State::FINISHED_LZW_DATA:
    536            return Transition::To(State::IMAGE_DATA_SUB_BLOCK,
    537                                  SUB_BLOCK_HEADER_LEN);
    538          case State::FINISH_END_IMAGE_FRAME:
    539            return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
    540          case State::SKIP_SUB_BLOCKS:
    541            return SkipSubBlocks(aData);
    542          case State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS:
    543            return Transition::ContinueUnbuffered(
    544                State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS);
    545          case State::FINISHED_SKIPPING_DATA:
    546            return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
    547          default:
    548            MOZ_CRASH("Unknown State");
    549        }
    550      });
    551 }
    552 
    553 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadGIFHeader(
    554    const char* aData) {
    555  // We retrieve the version here but because many GIF encoders set header
    556  // fields incorrectly, we barely use it; features which should only appear in
    557  // GIF89a are always accepted.
    558  if (strncmp(aData, "GIF87a", GIF_HEADER_LEN) == 0) {
    559    mGIFStruct.version = 87;
    560  } else if (strncmp(aData, "GIF89a", GIF_HEADER_LEN) == 0) {
    561    mGIFStruct.version = 89;
    562  } else {
    563    return Transition::TerminateFailure();
    564  }
    565 
    566  return Transition::To(State::SCREEN_DESCRIPTOR, GIF_SCREEN_DESCRIPTOR_LEN);
    567 }
    568 
    569 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadScreenDescriptor(
    570    const char* aData) {
    571  mGIFStruct.screen_width = LittleEndian::readUint16(aData + 0);
    572  mGIFStruct.screen_height = LittleEndian::readUint16(aData + 2);
    573 
    574  const uint8_t packedFields = aData[4];
    575 
    576  // XXX: Should we be capturing these values even if there is no global color
    577  // table?
    578  mGIFStruct.global_colormap_depth =
    579      (packedFields & PACKED_FIELDS_TABLE_DEPTH_MASK) + 1;
    580  mGIFStruct.global_colormap_count = 1 << mGIFStruct.global_colormap_depth;
    581 
    582  // We ignore several fields in the header. We don't care about the 'sort
    583  // flag', which indicates if the global color table's entries are sorted in
    584  // order of importance - if we need to render this image for a device with a
    585  // narrower color gamut than GIF supports we'll handle that at a different
    586  // layer. We have no use for the pixel aspect ratio as well. Finally, we
    587  // intentionally ignore the background color index, as implementing that
    588  // feature would not be web compatible - when a GIF image frame doesn't cover
    589  // the entire area of the image, the area that's not covered should always be
    590  // transparent.
    591 
    592  if (packedFields & PACKED_FIELDS_COLOR_TABLE_BIT) {
    593    MOZ_ASSERT(mColorTablePos == 0);
    594 
    595    // We read the global color table in unbuffered mode since it can be quite
    596    // large and it'd be preferable to avoid unnecessary copies.
    597    const size_t globalColorTableSize = 3 * mGIFStruct.global_colormap_count;
    598    return Transition::ToUnbuffered(State::FINISHED_GLOBAL_COLOR_TABLE,
    599                                    State::GLOBAL_COLOR_TABLE,
    600                                    globalColorTableSize);
    601  }
    602 
    603  return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
    604 }
    605 
    606 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadGlobalColorTable(
    607    const char* aData, size_t aLength) {
    608  uint8_t* dest =
    609      reinterpret_cast<uint8_t*>(mGIFStruct.global_colormap) + mColorTablePos;
    610  memcpy(dest, aData, aLength);
    611  mColorTablePos += aLength;
    612  return Transition::ContinueUnbuffered(State::GLOBAL_COLOR_TABLE);
    613 }
    614 
    615 LexerTransition<nsGIFDecoder2::State>
    616 nsGIFDecoder2::FinishedGlobalColorTable() {
    617  ConvertColormap(mGIFStruct.global_colormap, mGIFStruct.global_colormap_count);
    618  mColorTablePos = 0;
    619  return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
    620 }
    621 
    622 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadBlockHeader(
    623    const char* aData) {
    624  // Determine what type of block we're dealing with.
    625  switch (aData[0]) {
    626    case GIF_EXTENSION_INTRODUCER:
    627      return Transition::To(State::EXTENSION_HEADER, EXTENSION_HEADER_LEN);
    628 
    629    case GIF_IMAGE_SEPARATOR:
    630      return Transition::To(State::IMAGE_DESCRIPTOR, IMAGE_DESCRIPTOR_LEN);
    631 
    632    case GIF_TRAILER:
    633      FinishInternal();
    634      return Transition::TerminateSuccess();
    635 
    636    default:
    637      // If we get anything other than GIF_IMAGE_SEPARATOR,
    638      // GIF_EXTENSION_INTRODUCER, or GIF_TRAILER, there is extraneous data
    639      // between blocks. The GIF87a spec tells us to keep reading until we find
    640      // an image separator, but GIF89a says such a file is corrupt. We follow
    641      // GIF89a and bail out.
    642 
    643      if (mGIFStruct.images_decoded > 0) {
    644        // The file is corrupt, but we successfully decoded some frames, so we
    645        // may as well consider the decode successful and display them.
    646        FinishInternal();
    647        return Transition::TerminateSuccess();
    648      }
    649 
    650      // No images decoded; there is nothing to display.
    651      return Transition::TerminateFailure();
    652  }
    653 }
    654 
    655 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadExtensionHeader(
    656    const char* aData) {
    657  const uint8_t label = aData[0];
    658  const uint8_t extensionHeaderLength = aData[1];
    659 
    660  // If the extension header is zero length, just treat it as a block terminator
    661  // and move on to the next block immediately.
    662  if (extensionHeaderLength == 0) {
    663    return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
    664  }
    665 
    666  switch (label) {
    667    case GIF_GRAPHIC_CONTROL_LABEL:
    668      // The GIF spec mandates that the Control Extension header block length is
    669      // 4 bytes, and the parser for this block reads 4 bytes, so we must
    670      // enforce that the buffer contains at least this many bytes. If the GIF
    671      // specifies a different length, we allow that, so long as it's larger;
    672      // the additional data will simply be ignored.
    673      return Transition::To(
    674          State::GRAPHIC_CONTROL_EXTENSION,
    675          max<uint8_t>(extensionHeaderLength, GRAPHIC_CONTROL_EXTENSION_LEN));
    676 
    677    case GIF_APPLICATION_EXTENSION_LABEL:
    678      // Again, the spec specifies that an application extension header is 11
    679      // bytes, but for compatibility with GIFs in the wild, we allow deviation
    680      // from the spec. This is important for real-world compatibility, as GIFs
    681      // in the wild exist with application extension headers that are both
    682      // shorter and longer than 11 bytes. However, we only try to actually
    683      // interpret the application extension if the length is correct;
    684      // otherwise, we just skip the block unconditionally.
    685      return extensionHeaderLength == APPLICATION_EXTENSION_LEN
    686                 ? Transition::To(State::APPLICATION_IDENTIFIER,
    687                                  extensionHeaderLength)
    688                 : Transition::ToUnbuffered(
    689                       State::FINISHED_SKIPPING_DATA,
    690                       State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
    691                       extensionHeaderLength);
    692 
    693    default:
    694      // Skip over any other type of extension block, including comment and
    695      // plain text blocks.
    696      return Transition::ToUnbuffered(State::FINISHED_SKIPPING_DATA,
    697                                      State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
    698                                      extensionHeaderLength);
    699  }
    700 }
    701 
    702 LexerTransition<nsGIFDecoder2::State>
    703 nsGIFDecoder2::ReadGraphicControlExtension(const char* aData) {
    704  mGIFStruct.is_transparent = aData[0] & 0x1;
    705  mGIFStruct.tpixel = uint8_t(aData[3]);
    706  mGIFStruct.disposal_method = (aData[0] >> 2) & 0x7;
    707 
    708  if (mGIFStruct.disposal_method == 4) {
    709    // Some encoders (and apparently some specs) represent
    710    // DisposalMethod::RESTORE_PREVIOUS as 4, but 3 is used in the canonical
    711    // spec and is more popular, so we normalize to 3.
    712    mGIFStruct.disposal_method = 3;
    713  } else if (mGIFStruct.disposal_method > 4) {
    714    // This GIF is using a disposal method which is undefined in the spec.
    715    // Treat it as DisposalMethod::NOT_SPECIFIED.
    716    mGIFStruct.disposal_method = 0;
    717  }
    718 
    719  DisposalMethod method = DisposalMethod(mGIFStruct.disposal_method);
    720  if (method == DisposalMethod::CLEAR_ALL || method == DisposalMethod::CLEAR) {
    721    // We may have to display the background under this image during animation
    722    // playback, so we regard it as transparent.
    723    PostHasTransparency();
    724  }
    725 
    726  mGIFStruct.delay_time = LittleEndian::readUint16(aData + 1) * 10;
    727  if (!HasAnimation() && mGIFStruct.delay_time > 0) {
    728    PostIsAnimated(FrameTimeout::FromRawMilliseconds(mGIFStruct.delay_time));
    729  }
    730 
    731  return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
    732 }
    733 
    734 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadApplicationIdentifier(
    735    const char* aData) {
    736  if ((strncmp(aData, "NETSCAPE2.0", 11) == 0) ||
    737      (strncmp(aData, "ANIMEXTS1.0", 11) == 0)) {
    738    // This is a Netscape application extension block.
    739    return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
    740                          SUB_BLOCK_HEADER_LEN);
    741  }
    742 
    743  // This is an application extension we don't care about. Just skip it.
    744  return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
    745 }
    746 
    747 LexerTransition<nsGIFDecoder2::State>
    748 nsGIFDecoder2::ReadNetscapeExtensionSubBlock(const char* aData) {
    749  const uint8_t blockLength = aData[0];
    750  if (blockLength == 0) {
    751    // We hit the block terminator.
    752    return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
    753  }
    754 
    755  // We consume a minimum of 3 bytes in accordance with the specs for the
    756  // Netscape application extension block, such as they are.
    757  const size_t extensionLength = max<uint8_t>(blockLength, 3);
    758  return Transition::To(State::NETSCAPE_EXTENSION_DATA, extensionLength);
    759 }
    760 
    761 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadNetscapeExtensionData(
    762    const char* aData) {
    763  // Documentation for NETSCAPE2.0 / ANIMEXTS1.0 extensions can be found at:
    764  //   https://wiki.whatwg.org/wiki/GIF
    765  static const uint8_t NETSCAPE_LOOPING_EXTENSION_SUB_BLOCK_ID = 1;
    766  static const uint8_t NETSCAPE_BUFFERING_EXTENSION_SUB_BLOCK_ID = 2;
    767 
    768  const uint8_t subBlockID = aData[0] & 7;
    769  switch (subBlockID) {
    770    case NETSCAPE_LOOPING_EXTENSION_SUB_BLOCK_ID:
    771      // This is looping extension.
    772      mGIFStruct.loop_count = LittleEndian::readUint16(aData + 1);
    773      // Zero loop count is infinite animation loop request.
    774      if (mGIFStruct.loop_count == 0) {
    775        mGIFStruct.loop_count = -1;
    776      }
    777 
    778      return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
    779                            SUB_BLOCK_HEADER_LEN);
    780 
    781    case NETSCAPE_BUFFERING_EXTENSION_SUB_BLOCK_ID:
    782      // We allow, but ignore, this extension.
    783      return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
    784                            SUB_BLOCK_HEADER_LEN);
    785 
    786    default:
    787      return Transition::TerminateFailure();
    788  }
    789 }
    790 
    791 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadImageDescriptor(
    792    const char* aData) {
    793  // On the first frame, we don't need to yield, and none of the other checks
    794  // below apply, so we can just jump right into FinishImageDescriptor().
    795  if (mGIFStruct.images_decoded == 0) {
    796    return FinishImageDescriptor(aData);
    797  }
    798 
    799  if (!HasAnimation()) {
    800    // We should've already called PostIsAnimated(); this must be a corrupt
    801    // animated image with a first frame timeout of zero. Signal that we're
    802    // animated now, before the first-frame decode early exit below, so that
    803    // RasterImage can detect that this happened.
    804    PostIsAnimated(FrameTimeout::FromRawMilliseconds(0));
    805  }
    806 
    807  if (IsFirstFrameDecode()) {
    808    // We're about to get a second frame, but we only want the first. Stop
    809    // decoding now.
    810    FinishInternal();
    811    return Transition::TerminateSuccess();
    812  }
    813 
    814  MOZ_ASSERT(Size() == OutputSize(), "Downscaling an animated image?");
    815  return FinishImageDescriptor(aData);
    816 }
    817 
    818 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::FinishImageDescriptor(
    819    const char* aData) {
    820  OrientedIntRect frameRect;
    821 
    822  // Get image offsets with respect to the screen origin.
    823  frameRect.SetRect(
    824      LittleEndian::readUint16(aData + 0), LittleEndian::readUint16(aData + 2),
    825      LittleEndian::readUint16(aData + 4), LittleEndian::readUint16(aData + 6));
    826 
    827  if (!mGIFStruct.images_decoded) {
    828    // Work around GIF files where
    829    //   * at least one of the logical screen dimensions is smaller than the
    830    //     same dimension in the first image, or
    831    //   * GIF87a files where the first image's dimensions do not match the
    832    //     logical screen dimensions.
    833    if (mGIFStruct.screen_height < frameRect.Height() ||
    834        mGIFStruct.screen_width < frameRect.Width() ||
    835        mGIFStruct.version == 87) {
    836      mGIFStruct.screen_height = frameRect.Height();
    837      mGIFStruct.screen_width = frameRect.Width();
    838      frameRect.MoveTo(0, 0);
    839    }
    840 
    841    // Create the image container with the right size.
    842    BeginGIF();
    843    if (HasError()) {
    844      // Setting the size led to an error.
    845      return Transition::TerminateFailure();
    846    }
    847 
    848    // If we're doing a metadata decode without the frame count, we're done.
    849    if (IsMetadataDecode() && !WantsFrameCount()) {
    850      CheckForTransparency(frameRect);
    851      FinishInternal();
    852      return Transition::TerminateSuccess();
    853    }
    854  }
    855 
    856  // Work around broken GIF files that have zero frame width or height; in this
    857  // case, we'll treat the frame as having the same size as the overall image.
    858  if (frameRect.Height() == 0 || frameRect.Width() == 0) {
    859    frameRect.SetHeight(mGIFStruct.screen_height);
    860    frameRect.SetWidth(mGIFStruct.screen_width);
    861 
    862    // If that still resulted in zero frame width or height, give up.
    863    if (frameRect.Height() == 0 || frameRect.Width() == 0) {
    864      return Transition::TerminateFailure();
    865    }
    866  }
    867 
    868  // Determine |depth| (log base 2 of the number of colors in the palette).
    869  bool haveLocalColorTable = false;
    870  uint16_t depth = 0;
    871  uint8_t packedFields = aData[8];
    872 
    873  if (packedFields & PACKED_FIELDS_COLOR_TABLE_BIT) {
    874    // Get the palette depth from the local color table.
    875    depth = (packedFields & PACKED_FIELDS_TABLE_DEPTH_MASK) + 1;
    876    haveLocalColorTable = true;
    877  } else {
    878    // Get the palette depth from the global color table.
    879    depth = mGIFStruct.global_colormap_depth;
    880  }
    881 
    882  // If the transparent color index is greater than the number of colors in the
    883  // color table, we may need a higher color depth than |depth| would specify.
    884  // Our internal representation of the image will instead use |realDepth|,
    885  // which is the smallest color depth that can accommodate the existing palette
    886  // *and* the transparent color index.
    887  uint16_t realDepth = depth;
    888  while (mGIFStruct.tpixel >= (1 << realDepth) && realDepth < 8) {
    889    realDepth++;
    890  }
    891 
    892  // Create a mask used to ensure that color values fit within the colormap.
    893  mColorMask = 0xFF >> (8 - realDepth);
    894 
    895  // Determine if this frame is interlaced or not.
    896  const bool isInterlaced = packedFields & PACKED_FIELDS_INTERLACED_BIT;
    897 
    898  // Create the SurfacePipe we'll use to write output for this frame.
    899  if (NS_FAILED(BeginImageFrame(frameRect, realDepth, isInterlaced))) {
    900    return Transition::TerminateFailure();
    901  }
    902 
    903  // Clear state from last image.
    904  mGIFStruct.pixels_remaining =
    905      int64_t(frameRect.Width()) * int64_t(frameRect.Height());
    906 
    907  if (haveLocalColorTable) {
    908    // We have a local color table, so prepare to read it into the palette of
    909    // the current frame.
    910    mGIFStruct.local_colormap_size = 1 << depth;
    911 
    912    if (!mColormap) {
    913      // Ensure our current colormap buffer is large enough to hold the new one.
    914      mColormapSize = sizeof(uint32_t) << realDepth;
    915      if (mGIFStruct.local_colormap_buffer_size < mColormapSize) {
    916        if (mGIFStruct.local_colormap) {
    917          free(mGIFStruct.local_colormap);
    918        }
    919        mGIFStruct.local_colormap_buffer_size = mColormapSize;
    920        mGIFStruct.local_colormap =
    921            static_cast<uint32_t*>(moz_xmalloc(mColormapSize));
    922        // Ensure the local colormap is initialized as opaque.
    923        memset(mGIFStruct.local_colormap, 0xFF, mColormapSize);
    924      } else {
    925        mColormapSize = mGIFStruct.local_colormap_buffer_size;
    926      }
    927 
    928      mColormap = mGIFStruct.local_colormap;
    929    }
    930 
    931    MOZ_ASSERT(mColormap);
    932 
    933    const size_t size = 3 << depth;
    934    if (mColormapSize > size) {
    935      // Clear the part of the colormap which will be unused with this palette.
    936      // If a GIF references an invalid palette entry, ensure the entry is
    937      // opaque white. This is needed for Skia as if it isn't, RGBX surfaces
    938      // will cause blending issues with Skia.
    939      memset(reinterpret_cast<uint8_t*>(mColormap) + size, 0xFF,
    940             mColormapSize - size);
    941    }
    942 
    943    MOZ_ASSERT(mColorTablePos == 0);
    944 
    945    // We read the local color table in unbuffered mode since it can be quite
    946    // large and it'd be preferable to avoid unnecessary copies.
    947    return Transition::ToUnbuffered(State::FINISHED_LOCAL_COLOR_TABLE,
    948                                    State::LOCAL_COLOR_TABLE, size);
    949  }
    950 
    951  // There's no local color table; copy the global color table into the palette
    952  // of the current frame.
    953  if (mColormap) {
    954    memcpy(mColormap, mGIFStruct.global_colormap, mColormapSize);
    955  } else {
    956    mColormap = mGIFStruct.global_colormap;
    957  }
    958 
    959  return Transition::To(State::IMAGE_DATA_BLOCK, BLOCK_HEADER_LEN);
    960 }
    961 
    962 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadLocalColorTable(
    963    const char* aData, size_t aLength) {
    964  // If we are just counting frames for a metadata decode, there is no need to
    965  // prep the colormap.
    966  if (!WantsFrameCount()) {
    967    uint8_t* dest = reinterpret_cast<uint8_t*>(mColormap) + mColorTablePos;
    968    memcpy(dest, aData, aLength);
    969    mColorTablePos += aLength;
    970  }
    971  return Transition::ContinueUnbuffered(State::LOCAL_COLOR_TABLE);
    972 }
    973 
    974 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::FinishedLocalColorTable() {
    975  ConvertColormap(mColormap, mGIFStruct.local_colormap_size);
    976  mColorTablePos = 0;
    977  return Transition::To(State::IMAGE_DATA_BLOCK, BLOCK_HEADER_LEN);
    978 }
    979 
    980 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadImageDataBlock(
    981    const char* aData) {
    982  // Make sure the transparent pixel is transparent in the colormap.
    983  if (mGIFStruct.is_transparent) {
    984    // Save the old value so we can restore it later.
    985    if (mColormap == mGIFStruct.global_colormap) {
    986      mOldColor = mColormap[mGIFStruct.tpixel];
    987    }
    988    mColormap[mGIFStruct.tpixel] = 0;
    989  }
    990 
    991  // Initialize the LZW decoder.
    992  mGIFStruct.datasize = uint8_t(aData[0]);
    993  if (mGIFStruct.datasize > MAX_LZW_BITS) {
    994    return Transition::TerminateFailure();
    995  }
    996  const int clearCode = ClearCode();
    997  if (clearCode >= MAX_BITS) {
    998    return Transition::TerminateFailure();
    999  }
   1000 
   1001  mGIFStruct.avail = clearCode + 2;
   1002  mGIFStruct.oldcode = -1;
   1003  mGIFStruct.codesize = mGIFStruct.datasize + 1;
   1004  mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
   1005  mGIFStruct.datum = mGIFStruct.bits = 0;
   1006 
   1007  // Initialize the tables.
   1008  for (int i = 0; i < clearCode; i++) {
   1009    mGIFStruct.suffix[i] = i;
   1010  }
   1011 
   1012  mGIFStruct.stackp = mGIFStruct.stack;
   1013 
   1014  // Begin reading image data sub-blocks.
   1015  return Transition::To(State::IMAGE_DATA_SUB_BLOCK, SUB_BLOCK_HEADER_LEN);
   1016 }
   1017 
   1018 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadImageDataSubBlock(
   1019    const char* aData) {
   1020  const uint8_t subBlockLength = aData[0];
   1021  if (subBlockLength == 0) {
   1022    // We hit the block terminator. Yield if we are decoding multiple frames.
   1023    EndImageFrame();
   1024    if (IsFirstFrameDecode()) {
   1025      return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
   1026    }
   1027    return Transition::ToAfterYield(State::FINISH_END_IMAGE_FRAME);
   1028  }
   1029 
   1030  if (mGIFStruct.pixels_remaining == 0) {
   1031    // We've already written to the entire image; we should've hit the block
   1032    // terminator at this point. This image is corrupt, but we'll tolerate it.
   1033 
   1034    if (subBlockLength == GIF_TRAILER) {
   1035      // This GIF is missing the block terminator for the final block; we'll put
   1036      // up with it.
   1037      FinishInternal();
   1038      return Transition::TerminateSuccess();
   1039    }
   1040 
   1041    // We're not at the end of the image, so just skip the extra data.
   1042    return Transition::ToUnbuffered(State::FINISHED_LZW_DATA,
   1043                                    State::SKIP_LZW_DATA, subBlockLength);
   1044  }
   1045 
   1046  // Handle the standard case: there's data in the sub-block and pixels left to
   1047  // fill in the image. We read the sub-block unbuffered so we can get pixels on
   1048  // the screen as soon as possible.
   1049  return Transition::ToUnbuffered(State::FINISHED_LZW_DATA, State::LZW_DATA,
   1050                                  subBlockLength);
   1051 }
   1052 
   1053 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadLZWData(
   1054    const char* aData, size_t aLength) {
   1055  // If we are just counting frames for a metadata decode, there is no need to
   1056  // do the actual decode.
   1057  if (WantsFrameCount()) {
   1058    return Transition::ContinueUnbuffered(State::LZW_DATA);
   1059  }
   1060 
   1061  const uint8_t* data = reinterpret_cast<const uint8_t*>(aData);
   1062  size_t length = aLength;
   1063 
   1064  while (mGIFStruct.pixels_remaining > 0 &&
   1065         (length > 0 || mGIFStruct.bits >= mGIFStruct.codesize)) {
   1066    size_t bytesRead = 0;
   1067 
   1068    auto result = mPipe.WritePixelBlocks<uint32_t>(
   1069        [&](uint32_t* aPixelBlock, int32_t aBlockSize) {
   1070          return YieldPixels<uint32_t>(data, length, &bytesRead, aPixelBlock,
   1071                                       aBlockSize);
   1072        });
   1073 
   1074    if (MOZ_UNLIKELY(bytesRead > length)) {
   1075      MOZ_ASSERT_UNREACHABLE("Overread?");
   1076      bytesRead = length;
   1077    }
   1078 
   1079    // Advance our position in the input based upon what YieldPixel() consumed.
   1080    data += bytesRead;
   1081    length -= bytesRead;
   1082 
   1083    switch (result) {
   1084      case WriteState::NEED_MORE_DATA:
   1085        continue;
   1086 
   1087      case WriteState::FINISHED:
   1088        NS_WARNING_ASSERTION(mGIFStruct.pixels_remaining <= 0,
   1089                             "too many pixels");
   1090        mGIFStruct.pixels_remaining = 0;
   1091        break;
   1092 
   1093      case WriteState::FAILURE:
   1094        if (mGIFStruct.images_decoded > 0) {
   1095          return Transition::TerminateSuccess();
   1096        }
   1097        return Transition::TerminateFailure();
   1098    }
   1099  }
   1100 
   1101  // We're done, but keep going until we consume all the data in the sub-block.
   1102  return Transition::ContinueUnbuffered(State::LZW_DATA);
   1103 }
   1104 
   1105 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::SkipSubBlocks(
   1106    const char* aData) {
   1107  // In the SKIP_SUB_BLOCKS state we skip over data sub-blocks that we're not
   1108  // interested in. Blocks consist of a block header (which can be up to 255
   1109  // bytes in length) and a series of data sub-blocks. Each data sub-block
   1110  // consists of a single byte length value, followed by the data itself. A data
   1111  // sub-block with a length of zero terminates the overall block.
   1112  // SKIP_SUB_BLOCKS reads a sub-block length value. If it's zero, we've arrived
   1113  // at the next block. Otherwise, we enter the SKIP_DATA_THEN_SKIP_SUB_BLOCKS
   1114  // state to skip over the sub-block data and return to SKIP_SUB_BLOCKS at the
   1115  // start of the next sub-block.
   1116 
   1117  const uint8_t nextSubBlockLength = aData[0];
   1118  if (nextSubBlockLength == 0) {
   1119    // We hit the block terminator, so the sequence of data sub-blocks is over;
   1120    // begin processing another block.
   1121    return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
   1122  }
   1123 
   1124  // Skip to the next sub-block length value.
   1125  return Transition::ToUnbuffered(State::FINISHED_SKIPPING_DATA,
   1126                                  State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
   1127                                  nextSubBlockLength);
   1128 }
   1129 
   1130 Maybe<glean::impl::MemoryDistributionMetric> nsGIFDecoder2::SpeedMetric()
   1131    const {
   1132  return Some(glean::image_decode::speed_gif);
   1133 }
   1134 
   1135 }  // namespace image
   1136 }  // namespace mozilla