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