diff --git a/image/BMPFileHeaders.h b/image/BMPFileHeaders.h deleted file mode 100644 index e47b44ec182..00000000000 --- a/image/BMPFileHeaders.h +++ /dev/null @@ -1,84 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_image_BMPFileHeaders_h -#define mozilla_image_BMPFileHeaders_h - -#include -#include - -namespace mozilla { -namespace image { -namespace bmp { - -// This length is stored in the |bihsize| field of bmp::FileHeader. -struct InfoHeaderLength { - enum { - WIN_V2 = 12, - WIN_V3 = 40, - WIN_V4 = 108, - WIN_V5 = 124, - - // OS2_V1 is omitted; it's the same as WIN_V2. - OS2_V2_MIN = 16, // Minimum allowed value for OS2v2. - OS2_V2_MAX = 64, // Maximum allowed value for OS2v2. - }; -}; - -struct FileHeader { - char signature[2]; // String "BM". - uint32_t filesize; // File size; unreliable in practice. - int32_t reserved; // Zero. - uint32_t dataoffset; // Offset to raster data. - - // The length of the file header as defined in the BMP spec. - static const size_t LENGTH = 14; -}; - -struct XYZ { - int32_t x, y, z; -}; - -struct XYZTriple { - XYZ r, g, b; -}; - -struct V5InfoHeader { - uint32_t bihsize; // Header size - int32_t width; // Uint16 in OS/2 BMPs - int32_t height; // Uint16 in OS/2 BMPs - uint16_t planes; // =1 - uint16_t bpp; // Bits per pixel. - // The rest of the header is not available in WIN_V2/OS2_V1 BMP Files - uint32_t compression; // See Compression for valid values - uint32_t image_size; // (compressed) image size. Can be 0 if - // compression==0 - uint32_t xppm; // Pixels per meter, horizontal - uint32_t yppm; // Pixels per meter, vertical - uint32_t colors; // Used Colors - uint32_t important_colors; // Number of important colors. 0=all - uint32_t red_mask; // Bits used for red component - uint32_t green_mask; // Bits used for green component - uint32_t blue_mask; // Bits used for blue component - uint32_t alpha_mask; // Bits used for alpha component - uint32_t color_space; // 0x73524742=LCS_sRGB ... - // These members are unused unless color_space == LCS_CALIBRATED_RGB - XYZTriple white_point; // Logical white point - uint32_t gamma_red; // Red gamma component - uint32_t gamma_green; // Green gamma component - uint32_t gamma_blue; // Blue gamma component - uint32_t intent; // Rendering intent - // These members are unused unless color_space == LCS_PROFILE_* - uint32_t profile_offset; // Offset to profile data in bytes - uint32_t profile_size; // Size of profile data in bytes - uint32_t reserved; // =0 - - static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742; -}; - -} // namespace bmp -} // namespace image -} // namespace mozilla - -#endif // mozilla_image_BMPFileHeaders_h diff --git a/image/BMPHeaders.h b/image/BMPHeaders.h new file mode 100644 index 00000000000..e1579f2b247 --- /dev/null +++ b/image/BMPHeaders.h @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_image_BMPHeaders_h +#define mozilla_image_BMPHeaders_h + +#include +#include + +namespace mozilla { +namespace image { +namespace bmp { + +// The length of the file header as defined in the BMP spec. +static const size_t FILE_HEADER_LENGTH = 14; + +// This lengths of the info header for the different BMP versions. +struct InfoHeaderLength { + enum { + WIN_V2 = 12, + WIN_V3 = 40, + WIN_V4 = 108, + WIN_V5 = 124, + + // OS2_V1 is omitted; it's the same as WIN_V2. + OS2_V2_MIN = 16, // Minimum allowed value for OS2v2. + OS2_V2_MAX = 64, // Maximum allowed value for OS2v2. + }; +}; + +} // namespace bmp +} // namespace image +} // namespace mozilla + +#endif // mozilla_image_BMPHeaders_h diff --git a/image/decoders/nsBMPDecoder.cpp b/image/decoders/nsBMPDecoder.cpp index d82c396cecd..fad3169f9f0 100644 --- a/image/decoders/nsBMPDecoder.cpp +++ b/image/decoders/nsBMPDecoder.cpp @@ -25,28 +25,28 @@ // // WinBMPv2. // - First is a 14 byte file header that includes: the magic number ("BM"), -// file size, and offset to the pixel data (|dataoffset|). +// file size, and offset to the pixel data (|mDataOffset|). // - Next is a 12 byte info header which includes: the info header size -// (bihsize), width, height, number of color planes, and bits-per-pixel -// (|bpp|) which must be 1, 4, 8 or 24. -// - Next is the semi-optional color table, which has length 2^|bpp| and has 3 -// bytes per value (BGR). The color table is required if |bpp| is 1, 4, or 8. +// (mBIHSize), width, height, number of color planes, and bits-per-pixel +// (|mBpp|) which must be 1, 4, 8 or 24. +// - Next is the semi-optional color table, which has length 2^|mBpp| and has 3 +// bytes per value (BGR). The color table is required if |mBpp| is 1, 4, or 8. // - Next is an optional gap. -// - Next is the pixel data, which is pointed to by |dataoffset|. +// - Next is the pixel data, which is pointed to by |mDataOffset|. // // WinBMPv3. This is the most widely used version. // - It changed the info header to 40 bytes by taking the WinBMPv2 info // header, enlargening its width and height fields, and adding more fields -// including: a compression type (|compression|) and number of colors -// (|colors|). +// including: a compression type (|mCompression|) and number of colors +// (|mNumColors|). // - The semi-optional color table is now 4 bytes per value (BGR0), and its -// length is |colors|, or 2^|bpp| if |colors| is zero. -// - |compression| can be RGB (i.e. no compression), RLE4 (if bpp==4) or RLE8 -// (if bpp==8) values. +// length is |mNumColors|, or 2^|mBpp| if |mNumColors| is zero. +// - |mCompression| can be RGB (i.e. no compression), RLE4 (if |mBpp|==4) or +// RLE8 (if |mBpp|==8) values. // // WinBMPv3-NT. A variant of WinBMPv3. // - It did not change the info header layout from WinBMPv3. -// - |bpp| can now be 16 or 32, in which case |compression| can be RGB or the +// - |mBpp| can now be 16 or 32, in which case |mCompression| can be RGB or the // new BITFIELDS value; in the latter case an additional 12 bytes of color // bitfields follow the info header. // @@ -174,7 +174,7 @@ GetBMPLog() nsBMPDecoder::nsBMPDecoder(RasterImage* aImage) : Decoder(aImage) - , mLexer(Transition::To(State::FILE_HEADER, FileHeader::LENGTH)) + , mLexer(Transition::To(State::FILE_HEADER, FILE_HEADER_LENGTH)) , mIsWithinICO(false) , mMayHaveTransparency(false) , mDoesHaveTransparency(false) @@ -186,8 +186,6 @@ nsBMPDecoder::nsBMPDecoder(RasterImage* aImage) , mCurrentPos(0) , mAbsoluteModeNumPixels(0) { - memset(&mBFH, 0, sizeof(mBFH)); - memset(&mBIH, 0, sizeof(mBIH)); } nsBMPDecoder::~nsBMPDecoder() @@ -198,14 +196,14 @@ nsBMPDecoder::~nsBMPDecoder() int32_t nsBMPDecoder::GetBitsPerPixel() const { - return mBIH.bpp; + return mH.mBpp; } // Obtains the width from the internal BIH header. int32_t nsBMPDecoder::GetWidth() const { - return mBIH.width; + return mH.mWidth; } // Obtains the absolute value of the height from the internal BIH header. @@ -213,7 +211,7 @@ nsBMPDecoder::GetWidth() const int32_t nsBMPDecoder::GetHeight() const { - return abs(mBIH.height); + return abs(mH.mHeight); } // Obtains the internal output image buffer. @@ -227,11 +225,11 @@ nsBMPDecoder::GetImageData() int32_t nsBMPDecoder::GetCompressedImageSize() const { - // In the RGB case image_size might not be set, so compute it manually. + // In the RGB case mImageSize might not be set, so compute it manually. MOZ_ASSERT(mPixelRowSize != 0); - return mBIH.compression == Compression::RGB + return mH.mCompression == Compression::RGB ? mPixelRowSize * GetHeight() - : mBIH.image_size; + : mH.mImageSize; } void @@ -247,7 +245,7 @@ nsBMPDecoder::FinishInternal() if (!IsMetadataDecode() && HasSize()) { // Invalidate. - nsIntRect r(0, 0, mBIH.width, GetHeight()); + nsIntRect r(0, 0, mH.mWidth, GetHeight()); PostInvalidation(r); if (mDoesHaveTransparency) { @@ -400,11 +398,11 @@ nsBMPDecoder::RowBuffer() return reinterpret_cast(mDownscaler->RowBuffer()) + mCurrentPos; } - // Convert from row (1..height) to absolute line (0..height-1). - int32_t line = (mBIH.height < 0) - ? -mBIH.height - mCurrentRow + // Convert from row (1..mHeight) to absolute line (0..mHeight-1). + int32_t line = (mH.mHeight < 0) + ? -mH.mHeight - mCurrentRow : mCurrentRow - 1; - int32_t offset = line * mBIH.width + mCurrentPos; + int32_t offset = line * mH.mWidth + mCurrentPos; return reinterpret_cast(mImageData) + offset; } @@ -420,7 +418,7 @@ nsBMPDecoder::FinishRow() Some(invalidRect.mTargetSizeRect)); } } else { - PostInvalidation(IntRect(0, mCurrentRow, mBIH.width, 1)); + PostInvalidation(IntRect(0, mCurrentRow, mH.mWidth, 1)); } mCurrentRow--; } @@ -466,7 +464,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount) return; } -// The length of the bihsize field in the info header. +// The length of the mBIHSize field in the info header. static const uint32_t BIHSIZE_FIELD_LENGTH = 4; LexerTransition @@ -474,51 +472,44 @@ nsBMPDecoder::ReadFileHeader(const char* aData, size_t aLength) { mPreGapLength += aLength; - mBFH.signature[0] = aData[0]; - mBFH.signature[1] = aData[1]; - bool signatureOk = mBFH.signature[0] == 'B' && mBFH.signature[1] == 'M'; + bool signatureOk = aData[0] == 'B' && aData[1] == 'M'; if (!signatureOk) { PostDataError(); return Transition::Terminate(State::FAILURE); } - // Nb: this field is unreliable. In Windows BMPs it's the file size, but in - // OS/2 BMPs it's sometimes the size of the file and info headers. It doesn't - // matter because we don't consult it. - mBFH.filesize = LittleEndian::readUint32(aData + 2); + // We ignore the filesize (aData + 2) and reserved (aData + 6) fields. - mBFH.reserved = 0; - - mBFH.dataoffset = LittleEndian::readUint32(aData + 10); + mH.mDataOffset = LittleEndian::readUint32(aData + 10); return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH); } -// We read the info header in two steps: (a) read the bihsize field to +// We read the info header in two steps: (a) read the mBIHSize field to // determine how long the header is; (b) read the rest of the header. LexerTransition nsBMPDecoder::ReadInfoHeaderSize(const char* aData, size_t aLength) { mPreGapLength += aLength; - mBIH.bihsize = LittleEndian::readUint32(aData); + mH.mBIHSize = LittleEndian::readUint32(aData); - bool bihsizeOk = mBIH.bihsize == InfoHeaderLength::WIN_V2 || - mBIH.bihsize == InfoHeaderLength::WIN_V3 || - mBIH.bihsize == InfoHeaderLength::WIN_V4 || - mBIH.bihsize == InfoHeaderLength::WIN_V5 || - (mBIH.bihsize >= InfoHeaderLength::OS2_V2_MIN && - mBIH.bihsize <= InfoHeaderLength::OS2_V2_MAX); - if (!bihsizeOk) { + bool bihSizeOk = mH.mBIHSize == InfoHeaderLength::WIN_V2 || + mH.mBIHSize == InfoHeaderLength::WIN_V3 || + mH.mBIHSize == InfoHeaderLength::WIN_V4 || + mH.mBIHSize == InfoHeaderLength::WIN_V5 || + (mH.mBIHSize >= InfoHeaderLength::OS2_V2_MIN && + mH.mBIHSize <= InfoHeaderLength::OS2_V2_MAX); + if (!bihSizeOk) { PostDataError(); return Transition::Terminate(State::FAILURE); } // ICO BMPs must have a WinVMPv3 header. nsICODecoder should have already // terminated decoding if this isn't the case. - MOZ_ASSERT_IF(mIsWithinICO, mBIH.bihsize == InfoHeaderLength::WIN_V3); + MOZ_ASSERT_IF(mIsWithinICO, mH.mBIHSize == InfoHeaderLength::WIN_V3); return Transition::To(State::INFO_HEADER_REST, - mBIH.bihsize - BIHSIZE_FIELD_LENGTH); + mH.mBIHSize - BIHSIZE_FIELD_LENGTH); } LexerTransition @@ -526,28 +517,26 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength) { mPreGapLength += aLength; - // |width| and |height| may be signed (Windows) or unsigned (OS/2). We just + // |mWidth| and |mHeight| may be signed (Windows) or unsigned (OS/2). We just // read as unsigned because in practice that's good enough. - if (mBIH.bihsize == InfoHeaderLength::WIN_V2) { - mBIH.width = LittleEndian::readUint16(aData + 0); - mBIH.height = LittleEndian::readUint16(aData + 2); - mBIH.planes = LittleEndian::readUint16(aData + 4); - mBIH.bpp = LittleEndian::readUint16(aData + 6); + if (mH.mBIHSize == InfoHeaderLength::WIN_V2) { + mH.mWidth = LittleEndian::readUint16(aData + 0); + mH.mHeight = LittleEndian::readUint16(aData + 2); + // We ignore the planes (aData + 4) field; it should always be 1. + mH.mBpp = LittleEndian::readUint16(aData + 6); } else { - mBIH.width = LittleEndian::readUint32(aData + 0); - mBIH.height = LittleEndian::readUint32(aData + 4); - mBIH.planes = LittleEndian::readUint16(aData + 8); - mBIH.bpp = LittleEndian::readUint16(aData + 10); + mH.mWidth = LittleEndian::readUint32(aData + 0); + mH.mHeight = LittleEndian::readUint32(aData + 4); + // We ignore the planes (aData + 4) field; it should always be 1. + mH.mBpp = LittleEndian::readUint16(aData + 10); // For OS2-BMPv2 the info header may be as little as 16 bytes, so be // careful for these fields. - mBIH.compression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0; - mBIH.image_size = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0; - mBIH.xppm = aLength >= 24 ? LittleEndian::readUint32(aData + 20) : 0; - mBIH.yppm = aLength >= 28 ? LittleEndian::readUint32(aData + 24) : 0; - mBIH.colors = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0; - mBIH.important_colors - = aLength >= 36 ? LittleEndian::readUint32(aData + 32) : 0; + mH.mCompression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0; + mH.mImageSize = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0; + // We ignore the xppm (aData + 20) and yppm (aData + 24) fields. + mH.mNumColors = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0; + // We ignore the important_colors (aData + 36) field. // For WinBMPv4, WinBMPv5 and (possibly) OS2-BMPv2 there are additional // fields in the info header which we ignore, with the possible exception @@ -557,29 +546,29 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength) // Run with NSPR_LOG_MODULES=BMPDecoder:4 set to see this output. MOZ_LOG(GetBMPLog(), LogLevel::Debug, ("BMP: bihsize=%u, %d x %d, bpp=%u, compression=%u, colors=%u\n", - mBIH.bihsize, mBIH.width, mBIH.height, uint32_t(mBIH.bpp), - mBIH.compression, mBIH.colors)); + mH.mBIHSize, mH.mWidth, mH.mHeight, uint32_t(mH.mBpp), + mH.mCompression, mH.mNumColors)); // BMPs with negative width are invalid. Also, reject extremely wide images // to keep the math sane. And reject INT_MIN as a height because you can't // get its absolute value (because -INT_MIN is one more than INT_MAX). const int32_t k64KWidth = 0x0000FFFF; - bool sizeOk = 0 <= mBIH.width && mBIH.width <= k64KWidth && - mBIH.height != INT_MIN; + bool sizeOk = 0 <= mH.mWidth && mH.mWidth <= k64KWidth && + mH.mHeight != INT_MIN; if (!sizeOk) { PostDataError(); return Transition::Terminate(State::FAILURE); } - // Check bpp and compression. + // Check mBpp and mCompression. bool bppCompressionOk = - (mBIH.compression == Compression::RGB && - (mBIH.bpp == 1 || mBIH.bpp == 4 || mBIH.bpp == 8 || - mBIH.bpp == 16 || mBIH.bpp == 24 || mBIH.bpp == 32)) || - (mBIH.compression == Compression::RLE8 && mBIH.bpp == 8) || - (mBIH.compression == Compression::RLE4 && mBIH.bpp == 4) || - (mBIH.compression == Compression::BITFIELDS && - (mBIH.bpp == 16 || mBIH.bpp == 32)); + (mH.mCompression == Compression::RGB && + (mH.mBpp == 1 || mH.mBpp == 4 || mH.mBpp == 8 || + mH.mBpp == 16 || mH.mBpp == 24 || mH.mBpp == 32)) || + (mH.mCompression == Compression::RLE8 && mH.mBpp == 8) || + (mH.mCompression == Compression::RLE4 && mH.mBpp == 4) || + (mH.mCompression == Compression::BITFIELDS && + (mH.mBpp == 16 || mH.mBpp == 32)); if (!bppCompressionOk) { PostDataError(); return Transition::Terminate(State::FAILURE); @@ -587,22 +576,22 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength) // Post our size to the superclass. uint32_t realHeight = GetHeight(); - PostSize(mBIH.width, realHeight); + PostSize(mH.mWidth, realHeight); mCurrentRow = realHeight; // Round it up to the nearest byte count, then pad to 4-byte boundary. // Compute this even for a metadate decode because GetCompressedImageSize() // relies on it. - mPixelRowSize = (mBIH.bpp * mBIH.width + 7) / 8; + mPixelRowSize = (mH.mBpp * mH.mWidth + 7) / 8; uint32_t surplus = mPixelRowSize % 4; if (surplus != 0) { mPixelRowSize += 4 - surplus; } size_t bitFieldsLengthStillToRead = 0; - if (mBIH.compression == Compression::BITFIELDS) { + if (mH.mCompression == Compression::BITFIELDS) { // Need to read bitfields. - if (mBIH.bihsize >= InfoHeaderLength::WIN_V4) { + if (mH.mBIHSize >= InfoHeaderLength::WIN_V4) { // Bitfields are present in the info header, so we can read them // immediately. mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true); @@ -611,10 +600,10 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength) // ReadBitfields(). bitFieldsLengthStillToRead = BitFields::LENGTH; } - } else if (mBIH.bpp == 16) { + } else if (mH.mBpp == 16) { // No bitfields specified; use the default 5-5-5 values. mBitFields.SetR5G5B5(); - } else if (mBIH.bpp == 32) { + } else if (mH.mBpp == 32) { // No bitfields specified; use the default 8-8-8 values. mBitFields.SetR8G8B8(); } @@ -647,10 +636,10 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength) // Note that RLE-encoded BMPs might be transparent because the 'delta' mode // can skip pixels and cause implicit transparency. mMayHaveTransparency = - (mBIH.compression == Compression::RGB && mIsWithinICO && mBIH.bpp == 32) || - mBIH.compression == Compression::RLE8 || - mBIH.compression == Compression::RLE4 || - (mBIH.compression == Compression::BITFIELDS && + (mH.mCompression == Compression::RGB && mIsWithinICO && mH.mBpp == 32) || + mH.mCompression == Compression::RLE8 || + mH.mCompression == Compression::RLE4 || + (mH.mCompression == Compression::BITFIELDS && mBitFields.mAlpha.IsPresent()); if (mMayHaveTransparency) { PostHasTransparency(); @@ -663,10 +652,10 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength) } // Set up the color table, if present; it'll be filled in by ReadColorTable(). - if (mBIH.bpp <= 8) { - mNumColors = 1 << mBIH.bpp; - if (0 < mBIH.colors && mBIH.colors < mNumColors) { - mNumColors = mBIH.colors; + if (mH.mBpp <= 8) { + mNumColors = 1 << mH.mBpp; + if (0 < mH.mNumColors && mH.mNumColors < mNumColors) { + mNumColors = mH.mNumColors; } // Always allocate and zero 256 entries, even though mNumColors might be @@ -675,7 +664,7 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength) memset(mColors.get(), 0, 256 * sizeof(ColorTableEntry)); // OS/2 Bitmaps have no padding byte. - mBytesPerColor = (mBIH.bihsize == InfoHeaderLength::WIN_V2) ? 3 : 4; + mBytesPerColor = (mH.mBIHSize == InfoHeaderLength::WIN_V2) ? 3 : 4; } MOZ_ASSERT(!mImageData, "Already have a buffer allocated?"); @@ -718,25 +707,25 @@ nsBMPDecoder::ReadColorTable(const char* aData, size_t aLength) } // We know how many bytes we've read so far (mPreGapLength) and we know the - // offset of the pixel data (mBFH.dataoffset), so we can determine the length + // offset of the pixel data (mH.mDataOffset), so we can determine the length // of the gap (possibly zero) between the color table and the pixel data. // - // If the gap is negative the file must be malformed (e.g. mBFH.dataoffset + // If the gap is negative the file must be malformed (e.g. mH.mDataOffset // points into the middle of the color palette instead of past the end) and // we give up. - if (mPreGapLength > mBFH.dataoffset) { + if (mPreGapLength > mH.mDataOffset) { PostDataError(); return Transition::Terminate(State::FAILURE); } - uint32_t gapLength = mBFH.dataoffset - mPreGapLength; + uint32_t gapLength = mH.mDataOffset - mPreGapLength; return Transition::To(State::GAP, gapLength); } LexerTransition nsBMPDecoder::SkipGap() { - bool hasRLE = mBIH.compression == Compression::RLE8 || - mBIH.compression == Compression::RLE4; + bool hasRLE = mH.mCompression == Compression::RLE8 || + mH.mCompression == Compression::RLE4; return hasRLE ? Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH) : Transition::To(State::PIXEL_ROW, mPixelRowSize); @@ -749,8 +738,8 @@ nsBMPDecoder::ReadPixelRow(const char* aData) const uint8_t* src = reinterpret_cast(aData); uint32_t* dst = RowBuffer(); - uint32_t lpos = mBIH.width; - switch (mBIH.bpp) { + uint32_t lpos = mH.mWidth; + switch (mH.mBpp) { case 1: while (lpos > 0) { int8_t bit; @@ -817,8 +806,8 @@ nsBMPDecoder::ReadPixelRow(const char* aData) break; case 32: - if (mBIH.compression == Compression::RGB && mIsWithinICO && - mBIH.bpp == 32) { + if (mH.mCompression == Compression::RGB && mIsWithinICO && + mH.mBpp == 32) { // This is a special case only used for 32bpp WinBMPv3-ICO files, which // could be in either 0RGB or ARGB format. while (lpos > 0) { @@ -894,11 +883,11 @@ nsBMPDecoder::ReadRLESegment(const char* aData) // // Work around bitmaps that specify too many pixels. uint32_t pixelsNeeded = - std::min(mBIH.width - mCurrentPos, byte1); + std::min(mH.mWidth - mCurrentPos, byte1); if (pixelsNeeded) { uint32_t* dst = RowBuffer(); mCurrentPos += pixelsNeeded; - if (mBIH.compression == Compression::RLE8) { + if (mH.mCompression == Compression::RLE8) { do { SetPixel(dst, byte2, mColors); pixelsNeeded --; @@ -934,7 +923,7 @@ nsBMPDecoder::ReadRLESegment(const char* aData) MOZ_ASSERT(mAbsoluteModeNumPixels == 0); mAbsoluteModeNumPixels = byte2; uint32_t length = byte2; - if (mBIH.compression == Compression::RLE4) { + if (mH.mCompression == Compression::RLE4) { length = (length + 1) / 2; // halve, rounding up } if (length & 1) { @@ -959,8 +948,8 @@ nsBMPDecoder::ReadRLEDelta(const char* aData) // Handle the XDelta. mCurrentPos += uint8_t(aData[0]); - if (mCurrentPos > mBIH.width) { - mCurrentPos = mBIH.width; + if (mCurrentPos > mH.mWidth) { + mCurrentPos = mH.mWidth; } // Handle the Y Delta. @@ -989,7 +978,7 @@ nsBMPDecoder::ReadRLEAbsolute(const char* aData, size_t aLength) uint32_t n = mAbsoluteModeNumPixels; mAbsoluteModeNumPixels = 0; - if (mCurrentPos + n > uint32_t(mBIH.width)) { + if (mCurrentPos + n > uint32_t(mH.mWidth)) { // Bad data. Stop decoding; at least part of the image may have been // decoded. return Transition::Terminate(State::SUCCESS); @@ -1000,7 +989,7 @@ nsBMPDecoder::ReadRLEAbsolute(const char* aData, size_t aLength) uint32_t* dst = RowBuffer(); uint32_t iSrc = 0; uint32_t* oldPos = dst; - if (mBIH.compression == Compression::RLE8) { + if (mH.mCompression == Compression::RLE8) { while (n > 0) { SetPixel(dst, aData[iSrc], mColors); n--; diff --git a/image/decoders/nsBMPDecoder.h b/image/decoders/nsBMPDecoder.h index ca3829c1058..4af87dd2d8b 100644 --- a/image/decoders/nsBMPDecoder.h +++ b/image/decoders/nsBMPDecoder.h @@ -7,7 +7,7 @@ #ifndef mozilla_image_decoders_nsBMPDecoder_h #define mozilla_image_decoders_nsBMPDecoder_h -#include "BMPFileHeaders.h" +#include "BMPHeaders.h" #include "Decoder.h" #include "gfxColor.h" #include "StreamingLexer.h" @@ -18,6 +18,32 @@ namespace image { namespace bmp { +/// This struct contains the fields from the file header and info header that +/// we use during decoding. (Excluding bitfields fields, which are kept in +/// BitFields.) +struct Header { + uint32_t mDataOffset; // Offset to raster data. + uint32_t mBIHSize; // Header size. + int32_t mWidth; // Image width. + int32_t mHeight; // Image height. + uint16_t mBpp; // Bits per pixel. + uint32_t mCompression; // See struct Compression for valid values. + uint32_t mImageSize; // (compressed) image size. Can be 0 if + // mCompression==0. + uint32_t mNumColors; // Used colors. + + Header() + : mDataOffset(0) + , mBIHSize(0) + , mWidth(0) + , mHeight(0) + , mBpp(0) + , mCompression(0) + , mImageSize(0) + , mNumColors(0) + {} +}; + /// An entry in the color table. struct ColorTableEntry { uint8_t mRed; @@ -173,8 +199,7 @@ private: StreamingLexer mLexer; - bmp::FileHeader mBFH; - bmp::V5InfoHeader mBIH; + bmp::Header mH; // If the BMP is within an ICO file our treatment of it differs slightly. bool mIsWithinICO; diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index 982e941f855..4120fb0bf97 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -124,7 +124,7 @@ nsICODecoder::FillBitmapFileHeaderBuffer(int8_t* bfh) bfh[1] = 'M'; int32_t dataOffset = 0; int32_t fileSize = 0; - dataOffset = bmp::FileHeader::LENGTH + BITMAPINFOSIZE; + dataOffset = bmp::FILE_HEADER_LENGTH + BITMAPINFOSIZE; // The color table is present only if BPP is <= 8 if (mDirEntry.mBitCount <= 8) { diff --git a/image/encoders/bmp/nsBMPEncoder.cpp b/image/encoders/bmp/nsBMPEncoder.cpp index 40a902acb64..a92e3f667b5 100644 --- a/image/encoders/bmp/nsBMPEncoder.cpp +++ b/image/encoders/bmp/nsBMPEncoder.cpp @@ -487,9 +487,9 @@ nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth, mBMPFileHeader.signature[1] = 'M'; if (aVersion == VERSION_3) { - mBMPFileHeader.dataoffset = FileHeader::LENGTH + InfoHeaderLength::WIN_V3; + mBMPFileHeader.dataoffset = FILE_HEADER_LENGTH + InfoHeaderLength::WIN_V3; } else { // aVersion == 5 - mBMPFileHeader.dataoffset = FileHeader::LENGTH + InfoHeaderLength::WIN_V5; + mBMPFileHeader.dataoffset = FILE_HEADER_LENGTH + InfoHeaderLength::WIN_V5; } // The color table is present only if BPP is <= 8 diff --git a/image/encoders/bmp/nsBMPEncoder.h b/image/encoders/bmp/nsBMPEncoder.h index f2a9f0b3b5b..0d3a5e2146e 100644 --- a/image/encoders/bmp/nsBMPEncoder.h +++ b/image/encoders/bmp/nsBMPEncoder.h @@ -11,7 +11,7 @@ #include "mozilla/UniquePtr.h" #include "imgIEncoder.h" -#include "BMPFileHeaders.h" +#include "BMPHeaders.h" #include "nsCOMPtr.h" @@ -23,6 +23,62 @@ {0xbd, 0x16, 0xb0, 0x81, 0xa3, 0Xba, 0x8c, 0x0b} \ } +namespace mozilla { +namespace image { +namespace bmp { + +struct FileHeader { + char signature[2]; // String "BM". + uint32_t filesize; // File size. + int32_t reserved; // Zero. + uint32_t dataoffset; // Offset to raster data. +}; + +struct XYZ { + int32_t x, y, z; +}; + +struct XYZTriple { + XYZ r, g, b; +}; + +struct V5InfoHeader { + uint32_t bihsize; // Header size + int32_t width; // Uint16 in OS/2 BMPs + int32_t height; // Uint16 in OS/2 BMPs + uint16_t planes; // =1 + uint16_t bpp; // Bits per pixel. + uint32_t compression; // See Compression for valid values + uint32_t image_size; // (compressed) image size. Can be 0 if + // compression==0 + uint32_t xppm; // Pixels per meter, horizontal + uint32_t yppm; // Pixels per meter, vertical + uint32_t colors; // Used Colors + uint32_t important_colors; // Number of important colors. 0=all + // The rest of the header is not available in WIN_V3 BMP Files + uint32_t red_mask; // Bits used for red component + uint32_t green_mask; // Bits used for green component + uint32_t blue_mask; // Bits used for blue component + uint32_t alpha_mask; // Bits used for alpha component + uint32_t color_space; // 0x73524742=LCS_sRGB ... + // These members are unused unless color_space == LCS_CALIBRATED_RGB + XYZTriple white_point; // Logical white point + uint32_t gamma_red; // Red gamma component + uint32_t gamma_green; // Green gamma component + uint32_t gamma_blue; // Blue gamma component + uint32_t intent; // Rendering intent + // These members are unused unless color_space == LCS_PROFILE_* + uint32_t profile_offset; // Offset to profile data in bytes + uint32_t profile_size; // Size of profile data in bytes + uint32_t reserved; // =0 + + static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742; +}; + +} // namespace bmp +} // namespace image +} // namespace mozilla + // Provides BMP encoding functionality. Use InitFromData() to do the // encoding. See that function definition for encoding options. diff --git a/image/encoders/ico/nsICOEncoder.cpp b/image/encoders/ico/nsICOEncoder.cpp index 6d79552f79a..73d53e03772 100644 --- a/image/encoders/ico/nsICOEncoder.cpp +++ b/image/encoders/ico/nsICOEncoder.cpp @@ -162,10 +162,10 @@ nsICOEncoder::AddImageFrame(const uint8_t* aData, // Icon files that wrap a BMP file must not include the BITMAPFILEHEADER // section at the beginning of the encoded BMP data, so we must skip over - // bmp::FileHeader::LENGTH bytes when adding the BMP content to the icon + // bmp::FILE_HEADER_LENGTH bytes when adding the BMP content to the icon // file. mICODirEntry.mBytesInRes = - BMPImageBufferSize - bmp::FileHeader::LENGTH + andMaskSize; + BMPImageBufferSize - bmp::FILE_HEADER_LENGTH + andMaskSize; // Encode the icon headers EncodeFileHeader(); @@ -174,14 +174,14 @@ nsICOEncoder::AddImageFrame(const uint8_t* aData, char* imageBuffer; rv = mContainedEncoder->GetImageBuffer(&imageBuffer); NS_ENSURE_SUCCESS(rv, rv); - memcpy(mImageBufferCurr, imageBuffer + bmp::FileHeader::LENGTH, - BMPImageBufferSize - bmp::FileHeader::LENGTH); + memcpy(mImageBufferCurr, imageBuffer + bmp::FILE_HEADER_LENGTH, + BMPImageBufferSize - bmp::FILE_HEADER_LENGTH); // We need to fix the BMP height to be *2 for the AND mask uint32_t fixedHeight = GetRealHeight() * 2; NativeEndian::swapToLittleEndianInPlace(&fixedHeight, 1); // The height is stored at an offset of 8 from the DIB header memcpy(mImageBufferCurr + 8, &fixedHeight, sizeof(fixedHeight)); - mImageBufferCurr += BMPImageBufferSize - bmp::FileHeader::LENGTH; + mImageBufferCurr += BMPImageBufferSize - bmp::FILE_HEADER_LENGTH; // Calculate rowsize in DWORD's uint32_t rowSize = ((GetRealWidth() + 31) / 32) * 4; // + 31 to round up