tor-browser

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

nsBMPDecoder.cpp (46294B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 // This is a cross-platform BMP Decoder, which should work everywhere,
      8 // including big-endian machines like the PowerPC.
      9 //
     10 // BMP is a format that has been extended multiple times. To understand the
     11 // decoder you need to understand this history. The summary of the history
     12 // below was determined from the following documents.
     13 //
     14 // - http://www.fileformat.info/format/bmp/egff.htm
     15 // - http://www.fileformat.info/format/os2bmp/egff.htm
     16 // - http://fileformats.archiveteam.org/wiki/BMP
     17 // - http://fileformats.archiveteam.org/wiki/OS/2_BMP
     18 // - https://en.wikipedia.org/wiki/BMP_file_format
     19 // - https://upload.wikimedia.org/wikipedia/commons/c/c4/BMPfileFormat.png
     20 //
     21 // WINDOWS VERSIONS OF THE BMP FORMAT
     22 // ----------------------------------
     23 // WinBMPv1.
     24 // - This version is no longer used and can be ignored.
     25 //
     26 // WinBMPv2.
     27 // - First is a 14 byte file header that includes: the magic number ("BM"),
     28 //   file size, and offset to the pixel data (|mDataOffset|).
     29 // - Next is a 12 byte info header which includes: the info header size
     30 //   (mBIHSize), width, height, number of color planes, and bits-per-pixel
     31 //   (|mBpp|) which must be 1, 4, 8 or 24.
     32 // - Next is the semi-optional color table, which has length 2^|mBpp| and has 3
     33 //   bytes per value (BGR). The color table is required if |mBpp| is 1, 4, or 8.
     34 // - Next is an optional gap.
     35 // - Next is the pixel data, which is pointed to by |mDataOffset|.
     36 //
     37 // WinBMPv3. This is the most widely used version.
     38 // - It changed the info header to 40 bytes by taking the WinBMPv2 info
     39 //   header, enlargening its width and height fields, and adding more fields
     40 //   including: a compression type (|mCompression|) and number of colors
     41 //   (|mNumColors|).
     42 // - The semi-optional color table is now 4 bytes per value (BGR0), and its
     43 //   length is |mNumColors|, or 2^|mBpp| if |mNumColors| is zero.
     44 // - |mCompression| can be RGB (i.e. no compression), RLE4 (if |mBpp|==4) or
     45 //   RLE8 (if |mBpp|==8) values.
     46 //
     47 // WinBMPv3-NT. A variant of WinBMPv3.
     48 // - It did not change the info header layout from WinBMPv3.
     49 // - |mBpp| can now be 16 or 32, in which case |mCompression| can be RGB or the
     50 //   new BITFIELDS value; in the latter case an additional 12 bytes of color
     51 //   bitfields follow the info header.
     52 //
     53 // WinBMPv4.
     54 // - It extended the info header to 108 bytes, including the 12 bytes of color
     55 //   mask data from WinBMPv3-NT, plus alpha mask data, and also color-space and
     56 //   gamma correction fields.
     57 //
     58 // WinBMPv5.
     59 // - It extended the info header to 124 bytes, adding color profile data.
     60 // - It also added an optional color profile table after the pixel data (and
     61 //   another optional gap).
     62 //
     63 // WinBMPv3-ICO. This is a variant of WinBMPv3.
     64 // - It's the BMP format used for BMP images within ICO files.
     65 // - The only difference with WinBMPv3 is that if an image is 32bpp and has no
     66 //   compression, then instead of treating the pixel data as 0RGB it is treated
     67 //   as ARGB, but only if one or more of the A values are non-zero.
     68 //
     69 // Clipboard variants.
     70 // - It's the BMP format used for BMP images captured from the clipboard.
     71 // - It is missing the file header, containing the BM signature and the data
     72 //   offset. Instead the data begins after the header.
     73 // - If it uses BITFIELDS compression, then there is always an additional 12
     74 //   bytes of data after the header that must be read. In WinBMPv4+, the masks
     75 //   are supposed to be included in the header size, which are the values we use
     76 //   for decoding purposes, but there is additional three masks following the
     77 //   header which must be skipped to get to the pixel data.
     78 //
     79 // OS/2 VERSIONS OF THE BMP FORMAT
     80 // -------------------------------
     81 // OS2-BMPv1.
     82 // - Almost identical to WinBMPv2; the differences are basically ignorable.
     83 //
     84 // OS2-BMPv2.
     85 // - Similar to WinBMPv3.
     86 // - The info header is 64 bytes but can be reduced to as little as 16; any
     87 //   omitted fields are treated as zero. The first 40 bytes of these fields are
     88 //   nearly identical to the WinBMPv3 info header; the remaining 24 bytes are
     89 //   different.
     90 // - Also adds compression types "Huffman 1D" and "RLE24", which we don't
     91 //   support.
     92 // - We treat OS2-BMPv2 files as if they are WinBMPv3 (i.e. ignore the extra 24
     93 //   bytes in the info header), which in practice is good enough.
     94 
     95 #include "ImageLogging.h"
     96 #include "nsBMPDecoder.h"
     97 
     98 #include <stdlib.h>
     99 
    100 #include "mozilla/Attributes.h"
    101 #include "mozilla/EndianUtils.h"
    102 #include "mozilla/UniquePtrExtensions.h"
    103 
    104 #include "RasterImage.h"
    105 #include "SurfacePipeFactory.h"
    106 #include "gfxPlatform.h"
    107 #include <algorithm>
    108 
    109 using namespace mozilla::gfx;
    110 
    111 namespace mozilla {
    112 namespace image {
    113 namespace bmp {
    114 
    115 struct Compression {
    116  enum { RGB = 0, RLE8 = 1, RLE4 = 2, BITFIELDS = 3 };
    117 };
    118 
    119 // RLE escape codes and constants.
    120 struct RLE {
    121  enum {
    122    ESCAPE = 0,
    123    ESCAPE_EOL = 0,
    124    ESCAPE_EOF = 1,
    125    ESCAPE_DELTA = 2,
    126 
    127    SEGMENT_LENGTH = 2,
    128    DELTA_LENGTH = 2
    129  };
    130 };
    131 
    132 }  // namespace bmp
    133 
    134 using namespace bmp;
    135 
    136 static double FixedPoint2Dot30_To_Double(uint32_t aFixed) {
    137  constexpr double factor = 1.0 / 1073741824.0;  // 2^-30
    138  return double(aFixed) * factor;
    139 }
    140 
    141 static float FixedPoint16Dot16_To_Float(uint32_t aFixed) {
    142  constexpr double factor = 1.0 / 65536.0;  // 2^-16
    143  return double(aFixed) * factor;
    144 }
    145 
    146 static float CalRbgEndpointToQcms(const CalRgbEndpoint& aIn,
    147                                  qcms_CIE_xyY& aOut) {
    148  aOut.x = FixedPoint2Dot30_To_Double(aIn.mX);
    149  aOut.y = FixedPoint2Dot30_To_Double(aIn.mY);
    150  aOut.Y = FixedPoint2Dot30_To_Double(aIn.mZ);
    151  return FixedPoint16Dot16_To_Float(aIn.mGamma);
    152 }
    153 
    154 static void ReadCalRgbEndpoint(const char* aData, uint32_t aEndpointOffset,
    155                               uint32_t aGammaOffset, CalRgbEndpoint& aOut) {
    156  aOut.mX = LittleEndian::readUint32(aData + aEndpointOffset);
    157  aOut.mY = LittleEndian::readUint32(aData + aEndpointOffset + 4);
    158  aOut.mZ = LittleEndian::readUint32(aData + aEndpointOffset + 8);
    159  aOut.mGamma = LittleEndian::readUint32(aData + aGammaOffset);
    160 }
    161 
    162 /// Sets the pixel data in aDecoded to the given values.
    163 /// @param aDecoded pointer to pixel to be set, will be incremented to point to
    164 /// the next pixel.
    165 static void SetPixel(uint32_t*& aDecoded, uint8_t aRed, uint8_t aGreen,
    166                     uint8_t aBlue, uint8_t aAlpha = 0xFF) {
    167  *aDecoded++ = gfxPackedPixelNoPreMultiply(aAlpha, aRed, aGreen, aBlue);
    168 }
    169 
    170 static void SetPixel(uint32_t*& aDecoded, uint8_t idx,
    171                     const UniquePtr<ColorTableEntry[]>& aColors) {
    172  SetPixel(aDecoded, aColors[idx].mRed, aColors[idx].mGreen,
    173           aColors[idx].mBlue);
    174 }
    175 
    176 /// Sets two (or one if aCount = 1) pixels
    177 /// @param aDecoded where the data is stored. Will be moved 4 resp 8 bytes
    178 /// depending on whether one or two pixels are written.
    179 /// @param aData The values for the two pixels
    180 /// @param aCount Current count. Is decremented by one or two.
    181 static void Set4BitPixel(uint32_t*& aDecoded, uint8_t aData, uint32_t& aCount,
    182                         const UniquePtr<ColorTableEntry[]>& aColors) {
    183  uint8_t idx = aData >> 4;
    184  SetPixel(aDecoded, idx, aColors);
    185  if (--aCount > 0) {
    186    idx = aData & 0xF;
    187    SetPixel(aDecoded, idx, aColors);
    188    --aCount;
    189  }
    190 }
    191 
    192 static mozilla::LazyLogModule sBMPLog("BMPDecoder");
    193 
    194 // The length of the mBIHSize field in the info header.
    195 static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
    196 
    197 nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength,
    198                           bool aForClipboard)
    199    : Decoder(aImage),
    200      mLexer(Transition::To(aState, aLength), Transition::TerminateSuccess()),
    201      mIsWithinICO(false),
    202      mIsForClipboard(aForClipboard),
    203      mMayHaveTransparency(false),
    204      mDoesHaveTransparency(false),
    205      mNumColors(0),
    206      mColors(nullptr),
    207      mBytesPerColor(0),
    208      mPreGapLength(0),
    209      mPixelRowSize(0),
    210      mCurrentRow(0),
    211      mCurrentPos(0),
    212      mAbsoluteModeNumPixels(0) {}
    213 
    214 // Constructor for normal BMP files or from the clipboard.
    215 nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, bool aForClipboard)
    216    : nsBMPDecoder(aImage,
    217                   aForClipboard ? State::INFO_HEADER_SIZE : State::FILE_HEADER,
    218                   aForClipboard ? BIHSIZE_FIELD_LENGTH : FILE_HEADER_LENGTH,
    219                   aForClipboard) {}
    220 
    221 // Constructor used for WinBMPv3-ICO files, which lack a file header.
    222 nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset)
    223    : nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH,
    224                   /* aForClipboard */ false) {
    225  SetIsWithinICO();
    226 
    227  // Even though the file header isn't present in this case, the dataOffset
    228  // field is set as if it is, and so we must increment mPreGapLength
    229  // accordingly.
    230  mPreGapLength += FILE_HEADER_LENGTH;
    231 
    232  // This is the one piece of data we normally get from a BMP file header, so
    233  // it must be provided via an argument.
    234  mH.mDataOffset = aDataOffset;
    235 }
    236 
    237 nsBMPDecoder::~nsBMPDecoder() {}
    238 
    239 // Obtains the size of the compressed image resource.
    240 int32_t nsBMPDecoder::GetCompressedImageSize() const {
    241  // In the RGB case mImageSize might not be set, so compute it manually.
    242  MOZ_ASSERT(mPixelRowSize != 0);
    243  return mH.mCompression == Compression::RGB ? mPixelRowSize * AbsoluteHeight()
    244                                             : mH.mImageSize;
    245 }
    246 
    247 nsresult nsBMPDecoder::BeforeFinishInternal() {
    248  if (!IsMetadataDecode() && !mImageData) {
    249    return NS_ERROR_FAILURE;  // No image; something went wrong.
    250  }
    251 
    252  return NS_OK;
    253 }
    254 
    255 nsresult nsBMPDecoder::FinishInternal() {
    256  // We shouldn't be called in error cases.
    257  MOZ_ASSERT(!HasError(), "Can't call FinishInternal on error!");
    258 
    259  // We should never make multiple frames.
    260  MOZ_ASSERT(GetFrameCount() <= 1, "Multiple BMP frames?");
    261 
    262  // Send notifications if appropriate.
    263  if (!IsMetadataDecode() && HasSize()) {
    264    // We should have image data.
    265    MOZ_ASSERT(mImageData);
    266 
    267    // If it was truncated, fill in the missing pixels as black.
    268    while (mCurrentRow > 0) {
    269      uint32_t* dst = RowBuffer();
    270      while (mCurrentPos < mH.mWidth) {
    271        SetPixel(dst, 0, 0, 0);
    272        mCurrentPos++;
    273      }
    274      mCurrentPos = 0;
    275      FinishRow();
    276    }
    277 
    278    MOZ_ASSERT_IF(mDoesHaveTransparency, mMayHaveTransparency);
    279 
    280    // We have transparency if we either detected some in the image itself
    281    // (i.e., |mDoesHaveTransparency| is true) or we're in an ICO, which could
    282    // mean we have an AND mask that provides transparency (i.e., |mIsWithinICO|
    283    // is true).
    284    // XXX(seth): We can tell when we create the decoder if the AND mask is
    285    // present, so we could be more precise about this.
    286    const Opacity opacity = mDoesHaveTransparency || mIsWithinICO
    287                                ? Opacity::SOME_TRANSPARENCY
    288                                : Opacity::FULLY_OPAQUE;
    289 
    290    PostFrameStop(opacity);
    291    PostDecodeDone();
    292  }
    293 
    294  return NS_OK;
    295 }
    296 
    297 // ----------------------------------------
    298 // Actual Data Processing
    299 // ----------------------------------------
    300 
    301 void BitFields::Value::Set(uint32_t aMask) {
    302  mMask = aMask;
    303 
    304  // Handle this exceptional case first. The chosen values don't matter
    305  // (because a mask of zero will always give a value of zero) except that
    306  // mBitWidth:
    307  // - shouldn't be zero, because that would cause an infinite loop in Get();
    308  // - shouldn't be 5 or 8, because that could cause a false positive match in
    309  //   IsR5G5B5() or IsR8G8B8().
    310  if (mMask == 0x0) {
    311    mRightShift = 0;
    312    mBitWidth = 1;
    313    return;
    314  }
    315 
    316  // Find the rightmost 1.
    317  uint8_t i;
    318  for (i = 0; i < 32; i++) {
    319    if (mMask & (1 << i)) {
    320      break;
    321    }
    322  }
    323  mRightShift = i;
    324 
    325  // Now find the leftmost 1 in the same run of 1s. (If there are multiple runs
    326  // of 1s -- which isn't valid -- we'll behave as if only the lowest run was
    327  // present, which seems reasonable.)
    328  for (i = i + 1; i < 32; i++) {
    329    if (!(mMask & (1 << i))) {
    330      break;
    331    }
    332  }
    333  mBitWidth = i - mRightShift;
    334 }
    335 
    336 MOZ_ALWAYS_INLINE uint8_t BitFields::Value::Get(uint32_t aValue) const {
    337  // Extract the unscaled value.
    338  uint32_t v = (aValue & mMask) >> mRightShift;
    339 
    340  // Idea: to upscale v precisely we need to duplicate its bits, possibly
    341  // repeatedly, possibly partially in the last case, from bit 7 down to bit 0
    342  // in v2. For example:
    343  //
    344  // - mBitWidth=1:  v2 = v<<7 | v<<6 | ... | v<<1 | v>>0     k -> kkkkkkkk
    345  // - mBitWidth=2:  v2 = v<<6 | v<<4 | v<<2 | v>>0          jk -> jkjkjkjk
    346  // - mBitWidth=3:  v2 = v<<5 | v<<2 | v>>1                ijk -> ijkijkij
    347  // - mBitWidth=4:  v2 = v<<4 | v>>0                      hijk -> hijkhijk
    348  // - mBitWidth=5:  v2 = v<<3 | v>>2                     ghijk -> ghijkghi
    349  // - mBitWidth=6:  v2 = v<<2 | v>>4                    fghijk -> fghijkfg
    350  // - mBitWidth=7:  v2 = v<<1 | v>>6                   efghijk -> efghijke
    351  // - mBitWidth=8:  v2 = v>>0                         defghijk -> defghijk
    352  // - mBitWidth=9:  v2 = v>>1                        cdefghijk -> cdefghij
    353  // - mBitWidth=10: v2 = v>>2                       bcdefghijk -> bcdefghi
    354  // - mBitWidth=11: v2 = v>>3                      abcdefghijk -> abcdefgh
    355  // - etc.
    356  //
    357  uint8_t v2 = 0;
    358  int32_t i;  // must be a signed integer
    359  for (i = 8 - mBitWidth; i > 0; i -= mBitWidth) {
    360    v2 |= v << uint32_t(i);
    361  }
    362  v2 |= v >> uint32_t(-i);
    363  return v2;
    364 }
    365 
    366 MOZ_ALWAYS_INLINE uint8_t BitFields::Value::GetAlpha(uint32_t aValue,
    367                                                     bool& aHasAlphaOut) const {
    368  if (mMask == 0x0) {
    369    return 0xff;
    370  }
    371  aHasAlphaOut = true;
    372  return Get(aValue);
    373 }
    374 
    375 MOZ_ALWAYS_INLINE uint8_t BitFields::Value::Get5(uint32_t aValue) const {
    376  MOZ_ASSERT(mBitWidth == 5);
    377  uint32_t v = (aValue & mMask) >> mRightShift;
    378  return (v << 3u) | (v >> 2u);
    379 }
    380 
    381 MOZ_ALWAYS_INLINE uint8_t BitFields::Value::Get8(uint32_t aValue) const {
    382  MOZ_ASSERT(mBitWidth == 8);
    383  uint32_t v = (aValue & mMask) >> mRightShift;
    384  return v;
    385 }
    386 
    387 void BitFields::SetR5G5B5() {
    388  mRed.Set(0x7c00);
    389  mGreen.Set(0x03e0);
    390  mBlue.Set(0x001f);
    391 }
    392 
    393 void BitFields::SetR8G8B8() {
    394  mRed.Set(0xff0000);
    395  mGreen.Set(0xff00);
    396  mBlue.Set(0x00ff);
    397 }
    398 
    399 bool BitFields::IsR5G5B5() const {
    400  return mRed.mBitWidth == 5 && mGreen.mBitWidth == 5 && mBlue.mBitWidth == 5 &&
    401         mAlpha.mMask == 0x0;
    402 }
    403 
    404 bool BitFields::IsR8G8B8() const {
    405  return mRed.mBitWidth == 8 && mGreen.mBitWidth == 8 && mBlue.mBitWidth == 8 &&
    406         mAlpha.mMask == 0x0;
    407 }
    408 
    409 uint32_t* nsBMPDecoder::RowBuffer() { return mRowBuffer.get() + mCurrentPos; }
    410 
    411 void nsBMPDecoder::ClearRowBufferRemainder() {
    412  int32_t len = mH.mWidth - mCurrentPos;
    413  memset(RowBuffer(), mMayHaveTransparency ? 0 : 0xFF, len * sizeof(uint32_t));
    414 }
    415 
    416 void nsBMPDecoder::FinishRow() {
    417  mPipe.WriteBuffer(mRowBuffer.get());
    418  Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
    419  if (invalidRect) {
    420    PostInvalidation(invalidRect->mInputSpaceRect,
    421                     Some(invalidRect->mOutputSpaceRect));
    422  }
    423  mCurrentRow--;
    424 }
    425 
    426 LexerResult nsBMPDecoder::DoDecode(SourceBufferIterator& aIterator,
    427                                   IResumable* aOnResume) {
    428  MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
    429 
    430  return mLexer.Lex(
    431      aIterator, aOnResume,
    432      [=](State aState, const char* aData, size_t aLength) {
    433        switch (aState) {
    434          case State::FILE_HEADER:
    435            return ReadFileHeader(aData, aLength);
    436          case State::INFO_HEADER_SIZE:
    437            return ReadInfoHeaderSize(aData, aLength);
    438          case State::INFO_HEADER_REST:
    439            return ReadInfoHeaderRest(aData, aLength);
    440          case State::BITFIELDS:
    441            return ReadBitfields(aData, aLength);
    442          case State::SKIP_TO_COLOR_PROFILE:
    443            return Transition::ContinueUnbuffered(State::SKIP_TO_COLOR_PROFILE);
    444          case State::FOUND_COLOR_PROFILE:
    445            return Transition::To(State::COLOR_PROFILE,
    446                                  mH.mColorSpace.mProfile.mLength);
    447          case State::COLOR_PROFILE:
    448            return ReadColorProfile(aData, aLength);
    449          case State::ALLOCATE_SURFACE:
    450            return AllocateSurface();
    451          case State::COLOR_TABLE:
    452            return ReadColorTable(aData, aLength);
    453          case State::GAP:
    454            return SkipGap();
    455          case State::AFTER_GAP:
    456            return AfterGap();
    457          case State::PIXEL_ROW:
    458            return ReadPixelRow(aData);
    459          case State::RLE_SEGMENT:
    460            return ReadRLESegment(aData);
    461          case State::RLE_DELTA:
    462            return ReadRLEDelta(aData);
    463          case State::RLE_ABSOLUTE:
    464            return ReadRLEAbsolute(aData, aLength);
    465          default:
    466            MOZ_CRASH("Unknown State");
    467        }
    468      });
    469 }
    470 
    471 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadFileHeader(
    472    const char* aData, size_t aLength) {
    473  mPreGapLength += aLength;
    474 
    475  bool signatureOk = aData[0] == 'B' && aData[1] == 'M';
    476  if (!signatureOk) {
    477    return Transition::TerminateFailure();
    478  }
    479 
    480  // We ignore the filesize (aData + 2) and reserved (aData + 6) fields.
    481 
    482  mH.mDataOffset = LittleEndian::readUint32(aData + 10);
    483 
    484  return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
    485 }
    486 
    487 // We read the info header in two steps: (a) read the mBIHSize field to
    488 // determine how long the header is; (b) read the rest of the header.
    489 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadInfoHeaderSize(
    490    const char* aData, size_t aLength) {
    491  mH.mBIHSize = LittleEndian::readUint32(aData);
    492 
    493  // Data offset can be wrong so fix it using the BIH size.
    494  if (!mIsForClipboard && mH.mDataOffset < mPreGapLength + mH.mBIHSize) {
    495    mH.mDataOffset = mPreGapLength + mH.mBIHSize;
    496  }
    497 
    498  mPreGapLength += aLength;
    499 
    500  bool bihSizeOk = mH.mBIHSize == InfoHeaderLength::WIN_V2 ||
    501                   mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
    502                   mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
    503                   mH.mBIHSize == InfoHeaderLength::WIN_V5 ||
    504                   (mH.mBIHSize >= InfoHeaderLength::OS2_V2_MIN &&
    505                    mH.mBIHSize <= InfoHeaderLength::OS2_V2_MAX);
    506  if (!bihSizeOk) {
    507    return Transition::TerminateFailure();
    508  }
    509  // ICO BMPs must have a WinBMPv3 header. nsICODecoder should have already
    510  // terminated decoding if this isn't the case.
    511  MOZ_ASSERT_IF(mIsWithinICO, mH.mBIHSize == InfoHeaderLength::WIN_V3);
    512 
    513  return Transition::To(State::INFO_HEADER_REST,
    514                        mH.mBIHSize - BIHSIZE_FIELD_LENGTH);
    515 }
    516 
    517 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadInfoHeaderRest(
    518    const char* aData, size_t aLength) {
    519  mPreGapLength += aLength;
    520 
    521  // |mWidth| and |mHeight| may be signed (Windows) or unsigned (OS/2). We just
    522  // read as unsigned because in practice that's good enough.
    523  if (mH.mBIHSize == InfoHeaderLength::WIN_V2) {
    524    mH.mWidth = LittleEndian::readUint16(aData + 0);
    525    mH.mHeight = LittleEndian::readUint16(aData + 2);
    526    // We ignore the planes (aData + 4) field; it should always be 1.
    527    mH.mBpp = LittleEndian::readUint16(aData + 6);
    528  } else {
    529    mH.mWidth = LittleEndian::readUint32(aData + 0);
    530    mH.mHeight = LittleEndian::readUint32(aData + 4);
    531    // We ignore the planes (aData + 4) field; it should always be 1.
    532    mH.mBpp = LittleEndian::readUint16(aData + 10);
    533 
    534    // For OS2-BMPv2 the info header may be as little as 16 bytes, so be
    535    // careful for these fields.
    536    mH.mCompression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0;
    537    mH.mImageSize = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0;
    538    // We ignore the xppm (aData + 20) and yppm (aData + 24) fields.
    539    mH.mNumColors = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0;
    540    // We ignore the important_colors (aData + 36) field.
    541 
    542    // Read color management properties we may need later.
    543    mH.mCsType =
    544        aLength >= 56
    545            ? static_cast<InfoColorSpace>(LittleEndian::readUint32(aData + 52))
    546            : InfoColorSpace::SRGB;
    547    mH.mCsIntent = aLength >= 108 ? static_cast<InfoColorIntent>(
    548                                        LittleEndian::readUint32(aData + 104))
    549                                  : InfoColorIntent::IMAGES;
    550 
    551    switch (mH.mCsType) {
    552      case InfoColorSpace::CALIBRATED_RGB:
    553        if (aLength >= 104) {
    554          ReadCalRgbEndpoint(aData, 56, 92, mH.mColorSpace.mCalibrated.mRed);
    555          ReadCalRgbEndpoint(aData, 68, 96, mH.mColorSpace.mCalibrated.mGreen);
    556          ReadCalRgbEndpoint(aData, 80, 100, mH.mColorSpace.mCalibrated.mBlue);
    557        } else {
    558          mH.mCsType = InfoColorSpace::SRGB;
    559        }
    560        break;
    561      case InfoColorSpace::EMBEDDED:
    562        if (aLength >= 116) {
    563          mH.mColorSpace.mProfile.mOffset =
    564              LittleEndian::readUint32(aData + 108);
    565          mH.mColorSpace.mProfile.mLength =
    566              LittleEndian::readUint32(aData + 112);
    567        } else {
    568          mH.mCsType = InfoColorSpace::SRGB;
    569        }
    570        break;
    571      case InfoColorSpace::LINKED:
    572      case InfoColorSpace::SRGB:
    573      case InfoColorSpace::WIN:
    574      default:
    575        // Nothing to be done at this time.
    576        break;
    577    }
    578 
    579    // For WinBMPv4, WinBMPv5 and (possibly) OS2-BMPv2 there are additional
    580    // fields in the info header which we ignore, with the possible exception
    581    // of the color bitfields (see below).
    582  }
    583 
    584  // The height for BMPs embedded inside an ICO includes spaces for the AND
    585  // mask even if it is not present, thus we need to adjust for that here.
    586  if (mIsWithinICO) {
    587    // XXX(seth): Should we really be writing the absolute value from
    588    // the BIH below? Seems like this could be problematic for inverted BMPs.
    589    mH.mHeight = abs(mH.mHeight) / 2;
    590  }
    591 
    592  // Run with MOZ_LOG=BMPDecoder:5 set to see this output.
    593  MOZ_LOG(sBMPLog, LogLevel::Debug,
    594          ("BMP: bihsize=%u, %d x %d, bpp=%u, compression=%u, colors=%u, "
    595           "data-offset=%u\n",
    596           mH.mBIHSize, mH.mWidth, mH.mHeight, uint32_t(mH.mBpp),
    597           mH.mCompression, mH.mNumColors, mH.mDataOffset));
    598 
    599  // BMPs with negative width are invalid. Also, reject extremely wide images
    600  // to keep the math sane. And reject INT_MIN as a height because you can't
    601  // get its absolute value (because -INT_MIN is one more than INT_MAX).
    602  const int32_t k64KWidth = 0x0000FFFF;
    603  bool sizeOk =
    604      0 <= mH.mWidth && mH.mWidth <= k64KWidth && mH.mHeight != INT_MIN;
    605  if (!sizeOk) {
    606    return Transition::TerminateFailure();
    607  }
    608 
    609  // Check mBpp and mCompression.
    610  bool bppCompressionOk =
    611      (mH.mCompression == Compression::RGB &&
    612       (mH.mBpp == 1 || mH.mBpp == 4 || mH.mBpp == 8 || mH.mBpp == 16 ||
    613        mH.mBpp == 24 || mH.mBpp == 32)) ||
    614      (mH.mCompression == Compression::RLE8 && mH.mBpp == 8) ||
    615      (mH.mCompression == Compression::RLE4 && mH.mBpp == 4) ||
    616      (mH.mCompression == Compression::BITFIELDS &&
    617       // For BITFIELDS compression we require an exact match for one of the
    618       // WinBMP BIH sizes; this clearly isn't an OS2 BMP.
    619       (mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
    620        mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
    621        mH.mBIHSize == InfoHeaderLength::WIN_V5) &&
    622       (mH.mBpp == 16 || mH.mBpp == 32));
    623  if (!bppCompressionOk) {
    624    return Transition::TerminateFailure();
    625  }
    626 
    627  // Initialize our current row to the top of the image.
    628  mCurrentRow = AbsoluteHeight();
    629 
    630  // Round it up to the nearest byte count, then pad to 4-byte boundary.
    631  // Compute this even for a metadate decode because GetCompressedImageSize()
    632  // relies on it.
    633  mPixelRowSize = (mH.mBpp * mH.mWidth + 7) / 8;
    634  uint32_t surplus = mPixelRowSize % 4;
    635  if (surplus != 0) {
    636    mPixelRowSize += 4 - surplus;
    637  }
    638 
    639  size_t bitFieldsLengthStillToRead = 0;
    640  if (mH.mCompression == Compression::BITFIELDS) {
    641    // Need to read bitfields.
    642    if (mH.mBIHSize >= InfoHeaderLength::WIN_V4) {
    643      // Bitfields are present in the info header, so we can read them
    644      // immediately.
    645      mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true);
    646 
    647      // If this came from the clipboard, then we know that even if the header
    648      // explicitly includes the bitfield masks, we need to add an additional
    649      // offset for the start of the RGB data.
    650      if (mIsForClipboard) {
    651        mH.mDataOffset += BitFields::LENGTH;
    652      }
    653    } else {
    654      // Bitfields are present after the info header, so we will read them in
    655      // ReadBitfields().
    656      bitFieldsLengthStillToRead = BitFields::LENGTH;
    657    }
    658  } else if (mH.mBpp == 16) {
    659    // No bitfields specified; use the default 5-5-5 values.
    660    mBitFields.SetR5G5B5();
    661  } else if (mH.mBpp == 32) {
    662    // No bitfields specified; use the default 8-8-8 values.
    663    mBitFields.SetR8G8B8();
    664  }
    665 
    666  return Transition::To(State::BITFIELDS, bitFieldsLengthStillToRead);
    667 }
    668 
    669 void BitFields::ReadFromHeader(const char* aData, bool aReadAlpha) {
    670  mRed.Set(LittleEndian::readUint32(aData + 0));
    671  mGreen.Set(LittleEndian::readUint32(aData + 4));
    672  mBlue.Set(LittleEndian::readUint32(aData + 8));
    673  if (aReadAlpha) {
    674    mAlpha.Set(LittleEndian::readUint32(aData + 12));
    675  }
    676 }
    677 
    678 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadBitfields(
    679    const char* aData, size_t aLength) {
    680  mPreGapLength += aLength;
    681 
    682  // If aLength is zero there are no bitfields to read, or we already read them
    683  // in ReadInfoHeader().
    684  if (aLength != 0) {
    685    mBitFields.ReadFromHeader(aData, /* aReadAlpha = */ false);
    686  }
    687 
    688  // Note that RLE-encoded BMPs might be transparent because the 'delta' mode
    689  // can skip pixels and cause implicit transparency.
    690  mMayHaveTransparency = mIsWithinICO || mH.mCompression == Compression::RLE8 ||
    691                         mH.mCompression == Compression::RLE4 ||
    692                         (mH.mCompression == Compression::BITFIELDS &&
    693                          mBitFields.mAlpha.IsPresent());
    694  if (mMayHaveTransparency) {
    695    PostHasTransparency();
    696  }
    697 
    698  // Post our size to the superclass.
    699  PostSize(mH.mWidth, AbsoluteHeight());
    700  if (WantsFrameCount()) {
    701    PostFrameCount(/* aFrameCount */ 1);
    702  }
    703  if (HasError()) {
    704    return Transition::TerminateFailure();
    705  }
    706 
    707  // We've now read all the headers. If we're doing a metadata decode, we're
    708  // done.
    709  if (IsMetadataDecode()) {
    710    return Transition::TerminateSuccess();
    711  }
    712 
    713  // Set up the color table, if present; it'll be filled in by ReadColorTable().
    714  if (mH.mBpp <= 8) {
    715    mNumColors = 1 << mH.mBpp;
    716    if (0 < mH.mNumColors && mH.mNumColors < mNumColors) {
    717      mNumColors = mH.mNumColors;
    718    }
    719 
    720    // Always allocate and zero 256 entries, even though mNumColors might be
    721    // smaller, because the file might erroneously index past mNumColors.
    722    mColors = MakeUniqueFallible<ColorTableEntry[]>(256);
    723    if (NS_WARN_IF(!mColors)) {
    724      return Transition::TerminateFailure();
    725    }
    726    memset(mColors.get(), 0, 256 * sizeof(ColorTableEntry));
    727 
    728    // OS/2 Bitmaps have no padding byte.
    729    mBytesPerColor = (mH.mBIHSize == InfoHeaderLength::WIN_V2) ? 3 : 4;
    730  }
    731 
    732  if (mCMSMode != CMSMode::Off) {
    733    switch (mH.mCsType) {
    734      case InfoColorSpace::EMBEDDED:
    735        return SeekColorProfile(aLength);
    736      case InfoColorSpace::CALIBRATED_RGB:
    737        PrepareCalibratedColorProfile();
    738        break;
    739      case InfoColorSpace::SRGB:
    740      case InfoColorSpace::WIN:
    741        MOZ_LOG(sBMPLog, LogLevel::Debug, ("using sRGB color profile\n"));
    742        if (mColors) {
    743          // We will transform the color table instead of the output pixels.
    744          mTransform = GetCMSsRGBTransform(SurfaceFormat::R8G8B8);
    745        } else {
    746          mTransform = GetCMSsRGBTransform(SurfaceFormat::OS_RGBA);
    747        }
    748        break;
    749      case InfoColorSpace::LINKED:
    750      default:
    751        // Not supported, no color management.
    752        MOZ_LOG(sBMPLog, LogLevel::Debug, ("color space type not provided\n"));
    753        break;
    754    }
    755  }
    756 
    757  return Transition::To(State::ALLOCATE_SURFACE, 0);
    758 }
    759 
    760 void nsBMPDecoder::PrepareCalibratedColorProfile() {
    761  // BMP does not define a white point. Use the same as sRGB. This matches what
    762  // Chrome does as well.
    763  qcms_CIE_xyY white_point = qcms_white_point_sRGB();
    764 
    765  qcms_CIE_xyYTRIPLE primaries;
    766  float redGamma =
    767      CalRbgEndpointToQcms(mH.mColorSpace.mCalibrated.mRed, primaries.red);
    768  float greenGamma =
    769      CalRbgEndpointToQcms(mH.mColorSpace.mCalibrated.mGreen, primaries.green);
    770  float blueGamma =
    771      CalRbgEndpointToQcms(mH.mColorSpace.mCalibrated.mBlue, primaries.blue);
    772 
    773  // Explicitly verify the profile because sometimes the values from the BMP
    774  // header are just garbage.
    775  mInProfile = qcms_profile_create_rgb_with_gamma_set(
    776      white_point, primaries, redGamma, greenGamma, blueGamma);
    777  if (mInProfile && qcms_profile_is_bogus(mInProfile)) {
    778    // Bad profile, just use sRGB instead. Release the profile here, so that
    779    // our destructor doesn't assume we are the owner for the transform.
    780    qcms_profile_release(mInProfile);
    781    mInProfile = nullptr;
    782  }
    783 
    784  if (mInProfile) {
    785    MOZ_LOG(sBMPLog, LogLevel::Debug, ("using calibrated RGB color profile\n"));
    786    PrepareColorProfileTransform();
    787  } else {
    788    MOZ_LOG(sBMPLog, LogLevel::Debug,
    789            ("failed to create calibrated RGB color profile, using sRGB\n"));
    790    if (mColors) {
    791      // We will transform the color table instead of the output pixels.
    792      mTransform = GetCMSsRGBTransform(SurfaceFormat::R8G8B8);
    793    } else {
    794      mTransform = GetCMSsRGBTransform(SurfaceFormat::OS_RGBA);
    795    }
    796  }
    797 }
    798 
    799 void nsBMPDecoder::PrepareColorProfileTransform() {
    800  if (!mInProfile || !GetCMSOutputProfile()) {
    801    return;
    802  }
    803 
    804  qcms_data_type inType;
    805  qcms_data_type outType;
    806  if (mColors) {
    807    // We will transform the color table instead of the output pixels.
    808    inType = QCMS_DATA_RGB_8;
    809    outType = QCMS_DATA_RGB_8;
    810  } else {
    811    inType = gfxPlatform::GetCMSOSRGBAType();
    812    outType = inType;
    813  }
    814 
    815  qcms_intent intent;
    816  switch (mH.mCsIntent) {
    817    case InfoColorIntent::BUSINESS:
    818      intent = QCMS_INTENT_SATURATION;
    819      break;
    820    case InfoColorIntent::GRAPHICS:
    821      intent = QCMS_INTENT_RELATIVE_COLORIMETRIC;
    822      break;
    823    case InfoColorIntent::ABS_COLORIMETRIC:
    824      intent = QCMS_INTENT_ABSOLUTE_COLORIMETRIC;
    825      break;
    826    case InfoColorIntent::IMAGES:
    827    default:
    828      intent = QCMS_INTENT_PERCEPTUAL;
    829      break;
    830  }
    831 
    832  mTransform = qcms_transform_create(mInProfile, inType, GetCMSOutputProfile(),
    833                                     outType, intent);
    834  if (!mTransform) {
    835    MOZ_LOG(sBMPLog, LogLevel::Debug,
    836            ("failed to create color profile transform\n"));
    837  }
    838 }
    839 
    840 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::SeekColorProfile(
    841    size_t aLength) {
    842  // The offset needs to be at least after the color table.
    843  uint32_t offset = mH.mColorSpace.mProfile.mOffset;
    844  if (offset <= mH.mBIHSize + aLength + mNumColors * mBytesPerColor ||
    845      mH.mColorSpace.mProfile.mLength == 0) {
    846    return Transition::To(State::ALLOCATE_SURFACE, 0);
    847  }
    848 
    849  // We have already read the header and bitfields.
    850  offset -= mH.mBIHSize + aLength;
    851 
    852  // We need to skip ahead to search for the embedded color profile. We want
    853  // to return to this point once we read it.
    854  MOZ_ASSERT(!mReturnIterator.isSome());
    855  mReturnIterator = mLexer.Clone(*mIterator, SIZE_MAX);
    856  if (!mReturnIterator) {
    857    return Transition::TerminateFailure();
    858  }
    859 
    860  return Transition::ToUnbuffered(State::FOUND_COLOR_PROFILE,
    861                                  State::SKIP_TO_COLOR_PROFILE, offset);
    862 }
    863 
    864 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadColorProfile(
    865    const char* aData, size_t aLength) {
    866  mInProfile = qcms_profile_from_memory(aData, aLength);
    867  if (mInProfile) {
    868    MOZ_LOG(sBMPLog, LogLevel::Debug, ("using embedded color profile\n"));
    869    PrepareColorProfileTransform();
    870  }
    871 
    872  // Jump back to where we left off.
    873  MOZ_ASSERT(mReturnIterator.isSome());
    874  mIterator = std::move(mReturnIterator);
    875  return Transition::To(State::ALLOCATE_SURFACE, 0);
    876 }
    877 
    878 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::AllocateSurface() {
    879  SurfaceFormat format;
    880  SurfacePipeFlags pipeFlags = SurfacePipeFlags();
    881 
    882  if (mMayHaveTransparency) {
    883    format = SurfaceFormat::OS_RGBA;
    884    if (!(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA)) {
    885      pipeFlags |= SurfacePipeFlags::PREMULTIPLY_ALPHA;
    886    }
    887  } else {
    888    format = SurfaceFormat::OS_RGBX;
    889  }
    890 
    891  if (mH.mHeight >= 0) {
    892    // BMPs store their rows in reverse order, so we may need to flip.
    893    pipeFlags |= SurfacePipeFlags::FLIP_VERTICALLY;
    894  }
    895 
    896  mRowBuffer.reset(new (fallible) uint32_t[mH.mWidth]);
    897  if (!mRowBuffer) {
    898    return Transition::TerminateFailure();
    899  }
    900 
    901  // Only give the color transform to the SurfacePipe if we are not transforming
    902  // the color table in advance.
    903  qcms_transform* transform = mColors ? nullptr : mTransform;
    904 
    905  Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
    906      this, Size(), OutputSize(), FullFrame(), format, format, Nothing(),
    907      transform, pipeFlags);
    908  if (!pipe) {
    909    return Transition::TerminateFailure();
    910  }
    911 
    912  mPipe = std::move(*pipe);
    913  ClearRowBufferRemainder();
    914 
    915  // We might want to back track to here if we have a corrupt bmp that points
    916  // into the color table for image data, so save an iterator at this point.
    917  MOZ_ASSERT(!mReturnIterator.isSome());
    918  mReturnIterator = mLexer.Clone(*mIterator, SIZE_MAX);
    919  if (!mReturnIterator) {
    920    return Transition::TerminateFailure();
    921  }
    922 
    923  return Transition::To(State::COLOR_TABLE, mNumColors * mBytesPerColor);
    924 }
    925 
    926 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadColorTable(
    927    const char* aData, size_t aLength) {
    928  MOZ_ASSERT_IF(aLength != 0, mNumColors > 0 && mColors);
    929 
    930  mPreGapLength += aLength;
    931 
    932  for (uint32_t i = 0; i < mNumColors; i++) {
    933    // The format is BGR or BGR0.
    934    mColors[i].mBlue = uint8_t(aData[0]);
    935    mColors[i].mGreen = uint8_t(aData[1]);
    936    mColors[i].mRed = uint8_t(aData[2]);
    937    aData += mBytesPerColor;
    938  }
    939 
    940  // If we have a color table and a transform, we can avoid transforming each
    941  // pixel by doing the table in advance. We color manage every entry in the
    942  // table, even if it is smaller in case the BMP is malformed and overruns
    943  // its stated color range.
    944  if (mColors && mTransform) {
    945    qcms_transform_data(mTransform, mColors.get(), mColors.get(), 256);
    946  }
    947 
    948  // If we are decoding a BMP from the clipboard, we did not know the data
    949  // offset in advance. It is just defined as after the header and color table.
    950  if (mIsForClipboard) {
    951    mH.mDataOffset += mPreGapLength;
    952  }
    953 
    954  // We know how many bytes we've read so far (mPreGapLength) and we know the
    955  // offset of the pixel data (mH.mDataOffset), so we can determine the length
    956  // of the gap (possibly zero) between the color table and the pixel data.
    957  //
    958  // If the gap is negative the file must be malformed (e.g. mH.mDataOffset
    959  // points into the middle of the color palette instead of past the end).
    960  if (mPreGapLength > mH.mDataOffset) {
    961    // Allow corrupt bmp that say the image data starts in the color table, but
    962    // if the image data offset is even before the color tables thats too far
    963    // back and give up.
    964    if (mPreGapLength - aLength > mH.mDataOffset) {
    965      return Transition::TerminateFailure();
    966    }
    967    MOZ_ASSERT(mReturnIterator.isSome());
    968    mIterator = std::move(mReturnIterator);
    969    uint32_t gapLength = mH.mDataOffset - (mPreGapLength - aLength);
    970    return Transition::ToUnbuffered(State::AFTER_GAP, State::GAP, gapLength);
    971  }
    972 
    973  mReturnIterator.reset();
    974 
    975  uint32_t gapLength = mH.mDataOffset - mPreGapLength;
    976  return Transition::ToUnbuffered(State::AFTER_GAP, State::GAP, gapLength);
    977 }
    978 
    979 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::SkipGap() {
    980  return Transition::ContinueUnbuffered(State::GAP);
    981 }
    982 
    983 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::AfterGap() {
    984  // If there are no pixels we can stop.
    985  //
    986  // XXX: normally, if there are no pixels we will have stopped decoding before
    987  // now, outside of this decoder. However, if the BMP is within an ICO file,
    988  // it's possible that the ICO claimed the image had a non-zero size while the
    989  // BMP claims otherwise. This test is to catch that awkward case. If we ever
    990  // come up with a more general solution to this ICO-and-BMP-disagree-on-size
    991  // problem, this test can be removed.
    992  if (mH.mWidth == 0 || mH.mHeight == 0) {
    993    return Transition::TerminateSuccess();
    994  }
    995 
    996  bool hasRLE = mH.mCompression == Compression::RLE8 ||
    997                mH.mCompression == Compression::RLE4;
    998  return hasRLE ? Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH)
    999                : Transition::To(State::PIXEL_ROW, mPixelRowSize);
   1000 }
   1001 
   1002 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadPixelRow(
   1003    const char* aData) {
   1004  MOZ_ASSERT(mCurrentRow > 0);
   1005  MOZ_ASSERT(mCurrentPos == 0);
   1006 
   1007  const uint8_t* src = reinterpret_cast<const uint8_t*>(aData);
   1008  uint32_t* dst = RowBuffer();
   1009  uint32_t lpos = mH.mWidth;
   1010  switch (mH.mBpp) {
   1011    case 1:
   1012      while (lpos > 0) {
   1013        int8_t bit;
   1014        uint8_t idx;
   1015        for (bit = 7; bit >= 0 && lpos > 0; bit--) {
   1016          idx = (*src >> bit) & 1;
   1017          SetPixel(dst, idx, mColors);
   1018          --lpos;
   1019        }
   1020        ++src;
   1021      }
   1022      break;
   1023 
   1024    case 4:
   1025      while (lpos > 0) {
   1026        Set4BitPixel(dst, *src, lpos, mColors);
   1027        ++src;
   1028      }
   1029      break;
   1030 
   1031    case 8:
   1032      while (lpos > 0) {
   1033        SetPixel(dst, *src, mColors);
   1034        --lpos;
   1035        ++src;
   1036      }
   1037      break;
   1038 
   1039    case 16:
   1040      if (mBitFields.IsR5G5B5()) {
   1041        // Specialize this common case.
   1042        while (lpos > 0) {
   1043          uint16_t val = LittleEndian::readUint16(src);
   1044          SetPixel(dst, mBitFields.mRed.Get5(val), mBitFields.mGreen.Get5(val),
   1045                   mBitFields.mBlue.Get5(val));
   1046          --lpos;
   1047          src += 2;
   1048        }
   1049      } else {
   1050        bool anyHasAlpha = false;
   1051        while (lpos > 0) {
   1052          uint16_t val = LittleEndian::readUint16(src);
   1053          SetPixel(dst, mBitFields.mRed.Get(val), mBitFields.mGreen.Get(val),
   1054                   mBitFields.mBlue.Get(val),
   1055                   mBitFields.mAlpha.GetAlpha(val, anyHasAlpha));
   1056          --lpos;
   1057          src += 2;
   1058        }
   1059        if (anyHasAlpha) {
   1060          MOZ_ASSERT(mMayHaveTransparency);
   1061          mDoesHaveTransparency = true;
   1062        }
   1063      }
   1064      break;
   1065 
   1066    case 24:
   1067      while (lpos > 0) {
   1068        SetPixel(dst, src[2], src[1], src[0]);
   1069        --lpos;
   1070        src += 3;
   1071      }
   1072      break;
   1073 
   1074    case 32:
   1075      if (mH.mCompression == Compression::RGB && mIsWithinICO &&
   1076          mH.mBpp == 32) {
   1077        // This is a special case only used for 32bpp WinBMPv3-ICO files, which
   1078        // could be in either 0RGB or ARGB format. We start by assuming it's
   1079        // an 0RGB image. If we hit a non-zero alpha value, then we know it's
   1080        // actually an ARGB image, and change tack accordingly.
   1081        // (Note: a fully-transparent ARGB image is indistinguishable from a
   1082        // 0RGB image, and we will render such an image as a 0RGB image, i.e.
   1083        // opaquely. This is unlikely to be a problem in practice.)
   1084        while (lpos > 0) {
   1085          if (!mDoesHaveTransparency && src[3] != 0) {
   1086            // Up until now this looked like an 0RGB image, but we now know
   1087            // it's actually an ARGB image. Which means every pixel we've seen
   1088            // so far has been fully transparent. So we go back and redo them.
   1089 
   1090            // Tell the SurfacePipe to go back to the start.
   1091            mPipe.ResetToFirstRow();
   1092 
   1093            // Redo the complete rows we've already done.
   1094            MOZ_ASSERT(mCurrentPos == 0);
   1095            int32_t currentRow = mCurrentRow;
   1096            mCurrentRow = AbsoluteHeight();
   1097            ClearRowBufferRemainder();
   1098            while (mCurrentRow > currentRow) {
   1099              FinishRow();
   1100            }
   1101 
   1102            // Reset the row pointer back to where we started.
   1103            dst = RowBuffer() + (mH.mWidth - lpos);
   1104 
   1105            MOZ_ASSERT(mMayHaveTransparency);
   1106            mDoesHaveTransparency = true;
   1107          }
   1108 
   1109          // If mDoesHaveTransparency is false, treat this as an 0RGB image.
   1110          // Otherwise, treat this as an ARGB image.
   1111          SetPixel(dst, src[2], src[1], src[0],
   1112                   mDoesHaveTransparency ? src[3] : 0xff);
   1113          src += 4;
   1114          --lpos;
   1115        }
   1116      } else if (mBitFields.IsR8G8B8()) {
   1117        // Specialize this common case.
   1118        while (lpos > 0) {
   1119          uint32_t val = LittleEndian::readUint32(src);
   1120          SetPixel(dst, mBitFields.mRed.Get8(val), mBitFields.mGreen.Get8(val),
   1121                   mBitFields.mBlue.Get8(val));
   1122          --lpos;
   1123          src += 4;
   1124        }
   1125      } else {
   1126        bool anyHasAlpha = false;
   1127        while (lpos > 0) {
   1128          uint32_t val = LittleEndian::readUint32(src);
   1129          SetPixel(dst, mBitFields.mRed.Get(val), mBitFields.mGreen.Get(val),
   1130                   mBitFields.mBlue.Get(val),
   1131                   mBitFields.mAlpha.GetAlpha(val, anyHasAlpha));
   1132          --lpos;
   1133          src += 4;
   1134        }
   1135        if (anyHasAlpha) {
   1136          MOZ_ASSERT(mMayHaveTransparency);
   1137          mDoesHaveTransparency = true;
   1138        }
   1139      }
   1140      break;
   1141 
   1142    default:
   1143      MOZ_CRASH("Unsupported color depth; earlier check didn't catch it?");
   1144  }
   1145 
   1146  FinishRow();
   1147  return mCurrentRow == 0 ? Transition::TerminateSuccess()
   1148                          : Transition::To(State::PIXEL_ROW, mPixelRowSize);
   1149 }
   1150 
   1151 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadRLESegment(
   1152    const char* aData) {
   1153  if (mCurrentRow == 0) {
   1154    return Transition::TerminateSuccess();
   1155  }
   1156 
   1157  uint8_t byte1 = uint8_t(aData[0]);
   1158  uint8_t byte2 = uint8_t(aData[1]);
   1159 
   1160  if (byte1 != RLE::ESCAPE) {
   1161    // Encoded mode consists of two bytes: byte1 specifies the number of
   1162    // consecutive pixels to be drawn using the color index contained in
   1163    // byte2.
   1164    //
   1165    // Work around bitmaps that specify too many pixels.
   1166    uint32_t pixelsNeeded = std::min<uint32_t>(mH.mWidth - mCurrentPos, byte1);
   1167    if (pixelsNeeded) {
   1168      uint32_t* dst = RowBuffer();
   1169      mCurrentPos += pixelsNeeded;
   1170      if (mH.mCompression == Compression::RLE8) {
   1171        do {
   1172          SetPixel(dst, byte2, mColors);
   1173          pixelsNeeded--;
   1174        } while (pixelsNeeded);
   1175      } else {
   1176        do {
   1177          Set4BitPixel(dst, byte2, pixelsNeeded, mColors);
   1178        } while (pixelsNeeded);
   1179      }
   1180    }
   1181    return Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH);
   1182  }
   1183 
   1184  if (byte2 == RLE::ESCAPE_EOL) {
   1185    ClearRowBufferRemainder();
   1186    mCurrentPos = 0;
   1187    FinishRow();
   1188    return mCurrentRow == 0
   1189               ? Transition::TerminateSuccess()
   1190               : Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH);
   1191  }
   1192 
   1193  if (byte2 == RLE::ESCAPE_EOF) {
   1194    return Transition::TerminateSuccess();
   1195  }
   1196 
   1197  if (byte2 == RLE::ESCAPE_DELTA) {
   1198    return Transition::To(State::RLE_DELTA, RLE::DELTA_LENGTH);
   1199  }
   1200 
   1201  // Absolute mode. |byte2| gives the number of pixels. The length depends on
   1202  // whether it's 4-bit or 8-bit RLE. Also, the length must be even (and zero
   1203  // padding is used to achieve this when necessary).
   1204  MOZ_ASSERT(mAbsoluteModeNumPixels == 0);
   1205  mAbsoluteModeNumPixels = byte2;
   1206  uint32_t length = byte2;
   1207  if (mH.mCompression == Compression::RLE4) {
   1208    length = (length + 1) / 2;  // halve, rounding up
   1209  }
   1210  if (length & 1) {
   1211    length++;
   1212  }
   1213  return Transition::To(State::RLE_ABSOLUTE, length);
   1214 }
   1215 
   1216 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadRLEDelta(
   1217    const char* aData) {
   1218  // Delta encoding makes it possible to skip pixels making part of the image
   1219  // transparent.
   1220  MOZ_ASSERT(mMayHaveTransparency);
   1221  mDoesHaveTransparency = true;
   1222 
   1223  // Clear the skipped pixels. (This clears to the end of the row,
   1224  // which is perfect if there's a Y delta and harmless if not).
   1225  ClearRowBufferRemainder();
   1226 
   1227  // Handle the XDelta.
   1228  mCurrentPos += uint8_t(aData[0]);
   1229  if (mCurrentPos > mH.mWidth) {
   1230    mCurrentPos = mH.mWidth;
   1231  }
   1232 
   1233  // Handle the Y Delta.
   1234  int32_t yDelta = std::min<int32_t>(uint8_t(aData[1]), mCurrentRow);
   1235  if (yDelta > 0) {
   1236    // Commit the current row (the first of the skipped rows).
   1237    FinishRow();
   1238 
   1239    // Clear and commit the remaining skipped rows. We want to be careful not
   1240    // to change mCurrentPos here.
   1241    memset(mRowBuffer.get(), 0, mH.mWidth * sizeof(uint32_t));
   1242    for (int32_t line = 1; line < yDelta; line++) {
   1243      FinishRow();
   1244    }
   1245  }
   1246 
   1247  return mCurrentRow == 0
   1248             ? Transition::TerminateSuccess()
   1249             : Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH);
   1250 }
   1251 
   1252 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadRLEAbsolute(
   1253    const char* aData, size_t aLength) {
   1254  uint32_t n = mAbsoluteModeNumPixels;
   1255  mAbsoluteModeNumPixels = 0;
   1256 
   1257  if (mCurrentPos + n > uint32_t(mH.mWidth)) {
   1258    // Some DIB RLE8 encoders count a padding byte as the absolute mode
   1259    // pixel number at the end of the row.
   1260    if (mH.mCompression == Compression::RLE8 && n > 0 && (n & 1) == 0 &&
   1261        mCurrentPos + n - uint32_t(mH.mWidth) == 1 && aLength > 0 &&
   1262        aData[aLength - 1] == 0) {
   1263      n--;
   1264    } else {
   1265      // Bad data. Stop decoding; at least part of the image may have been
   1266      // decoded.
   1267      return Transition::TerminateSuccess();
   1268    }
   1269  }
   1270 
   1271  // In absolute mode, n represents the number of pixels that follow, each of
   1272  // which contains the color index of a single pixel.
   1273  uint32_t* dst = RowBuffer();
   1274  uint32_t iSrc = 0;
   1275  uint32_t* oldPos = dst;
   1276  if (mH.mCompression == Compression::RLE8) {
   1277    while (n > 0) {
   1278      SetPixel(dst, aData[iSrc], mColors);
   1279      n--;
   1280      iSrc++;
   1281    }
   1282  } else {
   1283    while (n > 0) {
   1284      Set4BitPixel(dst, aData[iSrc], n, mColors);
   1285      iSrc++;
   1286    }
   1287  }
   1288  mCurrentPos += dst - oldPos;
   1289 
   1290  // We should read all the data (unless the last byte is zero padding).
   1291  MOZ_ASSERT(iSrc == aLength - 1 || iSrc == aLength);
   1292 
   1293  return Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH);
   1294 }
   1295 
   1296 }  // namespace image
   1297 }  // namespace mozilla