1 /* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // I got the format description from http://www.daubnet.com/formats/BMP.html
8 // This is a Cross-Platform BMP Decoder, which should work everywhere, including
9 // Big-Endian machines like the PowerPC.
13 #include "ImageLogging.h"
14 #include "mozilla/Endian.h"
15 #include "mozilla/Likely.h"
16 #include "nsBMPDecoder.h"
18 #include "nsIInputStream.h"
19 #include "RasterImage.h"
26 static PRLogModuleInfo
*
29 static PRLogModuleInfo
* sBMPLog
;
31 sBMPLog
= PR_NewLogModule("BMPDecoder");
37 // Convert from row (1..height) to absolute line (0..height-1)
38 #define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
39 #define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
41 nsBMPDecoder::nsBMPDecoder(RasterImage
* aImage
)
44 , mLOH(WIN_V3_HEADER_LENGTH
)
49 , mCurLine(1) // Otherwise decoder will never start.
52 , mState(eRLEStateInitial
)
54 , mProcessedHeader(false)
55 , mUseAlphaData(false)
56 , mHaveAlphaData(false)
59 nsBMPDecoder::~nsBMPDecoder()
67 // Sets whether or not the BMP will use alpha data
69 nsBMPDecoder::SetUseAlphaData(bool useAlphaData
)
71 mUseAlphaData
= useAlphaData
;
74 // Obtains the bits per pixel from the internal BIH header
76 nsBMPDecoder::GetBitsPerPixel() const
81 // Obtains the width from the internal BIH header
83 nsBMPDecoder::GetWidth() const
88 // Obtains the abs-value of the height from the internal BIH header
90 nsBMPDecoder::GetHeight() const
92 return abs(mBIH
.height
);
95 // Obtains the internal output image buffer
97 nsBMPDecoder::GetImageData()
99 return reinterpret_cast<uint32_t*>(mImageData
);
102 // Obtains the size of the compressed image resource
104 nsBMPDecoder::GetCompressedImageSize() const
106 // For everything except BI_RGB the header field must be defined
107 if (mBIH
.compression
!= BI_RGB
) {
108 return mBIH
.image_size
;
111 // mBIH.image_size isn't always filled for BI_RGB so calculate it manually
112 // The pixel array size is calculated based on extra 4 byte boundary padding
113 uint32_t rowSize
= (mBIH
.bpp
* mBIH
.width
+ 7) / 8; // + 7 to round up
115 // Pad to DWORD Boundary
117 rowSize
+= (4 - (rowSize
% 4));
120 // The height should be the absolute value of what the height is in the BIH.
121 // If positive the bitmap is stored bottom to top, otherwise top to bottom
122 int32_t pixelArraySize
= rowSize
* GetHeight();
123 return pixelArraySize
;
126 // Obtains whether or not a BMP file had alpha data in its 4th byte
127 // for 32BPP bitmaps. Only use after the bitmap has been processed.
129 nsBMPDecoder::HasAlphaData() const
131 return mHaveAlphaData
;
136 nsBMPDecoder::FinishInternal()
138 // We shouldn't be called in error cases
139 NS_ABORT_IF_FALSE(!HasError(), "Can't call FinishInternal on error!");
141 // We should never make multiple frames
142 NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple BMP frames?");
144 // Send notifications if appropriate
145 if (!IsSizeDecode() && HasSize()) {
148 nsIntRect
r(0, 0, mBIH
.width
, GetHeight());
152 PostFrameStop(Opacity::SOME_TRANSPARENCY
);
154 PostFrameStop(Opacity::OPAQUE
);
160 // ----------------------------------------
161 // Actual Data Processing
162 // ----------------------------------------
165 calcBitmask(uint32_t aMask
, uint8_t& aBegin
, uint8_t& aLength
)
167 // find the rightmost 1
169 bool started
= false;
170 aBegin
= aLength
= 0;
171 for (pos
= 0; pos
<= 31; pos
++) {
172 if (!started
&& (aMask
& (1 << pos
))) {
175 } else if (started
&& !(aMask
& (1 << pos
))) {
176 aLength
= pos
- aBegin
;
183 nsBMPDecoder::CalcBitShift()
185 uint8_t begin
, length
;
187 calcBitmask(mBitFields
.red
, begin
, length
);
188 mBitFields
.redRightShift
= begin
;
189 mBitFields
.redLeftShift
= 8 - length
;
191 calcBitmask(mBitFields
.green
, begin
, length
);
192 mBitFields
.greenRightShift
= begin
;
193 mBitFields
.greenLeftShift
= 8 - length
;
195 calcBitmask(mBitFields
.blue
, begin
, length
);
196 mBitFields
.blueRightShift
= begin
;
197 mBitFields
.blueLeftShift
= 8 - length
;
202 nsBMPDecoder::WriteInternal(const char* aBuffer
, uint32_t aCount
)
204 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
206 // aCount=0 means EOF, mCurLine=0 means we're past end of image
207 if (!aCount
|| !mCurLine
) {
211 // This code assumes that mRawBuf == WIN_V3_INTERNAL_BIH_LENGTH
212 // and that sizeof(mRawBuf) >= BFH_INTERNAL_LENGTH
213 MOZ_ASSERT(sizeof(mRawBuf
) == WIN_V3_INTERNAL_BIH_LENGTH
);
214 MOZ_ASSERT(sizeof(mRawBuf
) >= BFH_INTERNAL_LENGTH
);
215 MOZ_ASSERT(OS2_INTERNAL_BIH_LENGTH
< WIN_V3_INTERNAL_BIH_LENGTH
);
217 // This code also assumes it's working with a byte array
218 MOZ_ASSERT(sizeof(mRawBuf
[0]) == 1);
220 if (mPos
< BFH_INTERNAL_LENGTH
) { /* In BITMAPFILEHEADER */
221 // BFH_INTERNAL_LENGTH < sizeof(mRawBuf)
222 // mPos < BFH_INTERNAL_LENGTH
223 // BFH_INTERNAL_LENGTH - mPos < sizeof(mRawBuf)
224 // so toCopy <= BFH_INTERNAL_LENGTH
225 // so toCopy < sizeof(mRawBuf)
226 // so toCopy > 0 && toCopy <= BFH_INTERNAL_LENGTH
227 uint32_t toCopy
= BFH_INTERNAL_LENGTH
- mPos
;
228 if (toCopy
> aCount
) {
232 // mRawBuf is a byte array of size WIN_V3_INTERNAL_BIH_LENGTH
234 // mPos is < BFH_INTERNAL_LENGTH
235 // BFH_INTERNAL_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
236 // so mPos < sizeof(mRawBuf)
238 // Therefore this assert should hold
239 MOZ_ASSERT(mPos
< sizeof(mRawBuf
));
241 // toCopy <= BFH_INTERNAL_LENGTH
242 // mPos >= 0 && mPos < BFH_INTERNAL_LENGTH
243 // sizeof(mRawBuf) >= BFH_INTERNAL_LENGTH (verified above)
245 // Therefore this assert should hold
246 MOZ_ASSERT(mPos
+ toCopy
<= sizeof(mRawBuf
));
248 memcpy(mRawBuf
+ mPos
, aBuffer
, toCopy
);
253 if (mPos
== BFH_INTERNAL_LENGTH
) {
255 if (mBFH
.signature
[0] != 'B' || mBFH
.signature
[1] != 'M') {
259 if (mBFH
.bihsize
== OS2_BIH_LENGTH
) {
260 mLOH
= OS2_HEADER_LENGTH
;
263 if (mPos
>= BFH_INTERNAL_LENGTH
&& mPos
< mLOH
) { /* In BITMAPINFOHEADER */
264 // mLOH == WIN_V3_HEADER_LENGTH || mLOH == OS2_HEADER_LENGTH
265 // OS2_HEADER_LENGTH < WIN_V3_HEADER_LENGTH
266 // BFH_INTERNAL_LENGTH < OS2_HEADER_LENGTH
267 // BFH_INTERNAL_LENGTH < WIN_V3_HEADER_LENGTH
269 // So toCopy is in the range
270 // 1 to (WIN_V3_HEADER_LENGTH - BFH_INTERNAL_LENGTH)
271 // or 1 to (OS2_HEADER_LENGTH - BFH_INTERNAL_LENGTH)
273 // But WIN_V3_HEADER_LENGTH =
274 // BFH_INTERNAL_LENGTH + WIN_V3_INTERNAL_BIH_LENGTH
275 // and OS2_HEADER_LENGTH = BFH_INTERNAL_LENGTH + OS2_INTERNAL_BIH_LENGTH
277 // So toCopy is in the range
279 // 1 to WIN_V3_INTERNAL_BIH_LENGTH
280 // or 1 to OS2_INTERNAL_BIH_LENGTH
281 // and OS2_INTERNAL_BIH_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
283 // sizeof(mRawBuf) = WIN_V3_INTERNAL_BIH_LENGTH
284 // so toCopy <= sizeof(mRawBuf)
285 uint32_t toCopy
= mLOH
- mPos
;
286 if (toCopy
> aCount
) {
290 // mPos is in the range
291 // BFH_INTERNAL_LENGTH to (WIN_V3_HEADER_LENGTH - 1)
293 // offset is then in the range (see toCopy comments for more details)
294 // 0 to (WIN_V3_INTERNAL_BIH_LENGTH - 1)
296 // sizeof(mRawBuf) is WIN_V3_INTERNAL_BIH_LENGTH so this
297 // offset stays within bounds and this assert should hold
298 const uint32_t offset
= mPos
- BFH_INTERNAL_LENGTH
;
299 MOZ_ASSERT(offset
< sizeof(mRawBuf
));
302 // mPos = BFH_INTERNAL_LENGTH
303 // mLOH = WIN_V3_HEADER_LENGTH
306 // toCopy = WIN_V3_INTERNAL_BIH_LENGTH
308 // This will be in the bounds of sizeof(mRawBuf)
311 // mPos = WIN_V3_HEADER_LENGTH - 1
312 // mLOH = WIN_V3_HEADER_LENGTH
314 // offset = WIN_V3_INTERNAL_BIH_LENGTH - 1
317 // This will be in the bounds of sizeof(mRawBuf)
319 // As sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH (verified above)
320 // and WIN_V3_HEADER_LENGTH is the largest range of values. If mLOH
321 // was equal to OS2_HEADER_LENGTH then the ranges are smaller.
322 MOZ_ASSERT(offset
+ toCopy
<= sizeof(mRawBuf
));
324 memcpy(mRawBuf
+ offset
, aBuffer
, toCopy
);
330 // At this point mPos should be >= mLOH unless aBuffer did not have enough
331 // data. In the latter case aCount should be 0.
332 MOZ_ASSERT(mPos
>= mLOH
|| aCount
== 0);
334 // mProcessedHeader is checked to ensure that if at this point mPos == mLOH
335 // but we have no data left to process, the next time WriteInternal is called
336 // we won't enter this condition again.
337 if (mPos
== mLOH
&& !mProcessedHeader
) {
338 mProcessedHeader
= true;
341 PR_LOG(GetBMPLog(), PR_LOG_DEBUG
,
342 ("BMP is %lix%lix%lu. compression=%lu\n",
343 mBIH
.width
, mBIH
.height
, mBIH
.bpp
, mBIH
.compression
));
344 // Verify we support this bit depth
345 if (mBIH
.bpp
!= 1 && mBIH
.bpp
!= 4 && mBIH
.bpp
!= 8 &&
346 mBIH
.bpp
!= 16 && mBIH
.bpp
!= 24 && mBIH
.bpp
!= 32) {
351 // BMPs with negative width are invalid
352 // Reject extremely wide images to keep the math sane
353 const int32_t k64KWidth
= 0x0000FFFF;
354 if (mBIH
.width
< 0 || mBIH
.width
> k64KWidth
) {
359 if (mBIH
.height
== INT_MIN
) {
364 uint32_t real_height
= GetHeight();
366 // Post our size to the superclass
367 PostSize(mBIH
.width
, real_height
);
369 // Setting the size led to an error.
373 // We have the size. If we're doing a size decode, we got what
375 if (IsSizeDecode()) {
379 // We're doing a real decode.
380 mOldLine
= mCurLine
= real_height
;
383 mNumColors
= 1 << mBIH
.bpp
;
384 if (mBIH
.colors
&& mBIH
.colors
< mNumColors
) {
385 mNumColors
= mBIH
.colors
;
388 // Always allocate 256 even though mNumColors might be smaller
389 mColors
= new colorTable
[256];
390 memset(mColors
, 0, 256 * sizeof(colorTable
));
391 } else if (mBIH
.compression
!= BI_BITFIELDS
&& mBIH
.bpp
== 16) {
392 // Use default 5-5-5 format
393 mBitFields
.red
= 0x7C00;
394 mBitFields
.green
= 0x03E0;
395 mBitFields
.blue
= 0x001F;
399 // Make sure we have a valid value for our supported compression modes
400 // before adding the frame
401 if (mBIH
.compression
!= BI_RGB
&& mBIH
.compression
!= BI_RLE8
&&
402 mBIH
.compression
!= BI_RLE4
&& mBIH
.compression
!= BI_BITFIELDS
) {
407 // If we have RLE4 or RLE8 or BI_ALPHABITFIELDS, then ensure we
408 // have valid BPP values before adding the frame
409 if (mBIH
.compression
== BI_RLE8
&& mBIH
.bpp
!= 8) {
410 PR_LOG(GetBMPLog(), PR_LOG_DEBUG
,
411 ("BMP RLE8 compression only supports 8 bits per pixel\n"));
415 if (mBIH
.compression
== BI_RLE4
&& mBIH
.bpp
!= 4 && mBIH
.bpp
!= 1) {
416 PR_LOG(GetBMPLog(), PR_LOG_DEBUG
,
417 ("BMP RLE4 compression only supports 4 bits per pixel\n"));
421 if (mBIH
.compression
== BI_ALPHABITFIELDS
&&
422 mBIH
.bpp
!= 16 && mBIH
.bpp
!= 32) {
423 PR_LOG(GetBMPLog(), PR_LOG_DEBUG
,
424 ("BMP ALPHABITFIELDS only supports 16 or 32 bits per pixel\n"
430 if (mBIH
.compression
!= BI_RLE8
&& mBIH
.compression
!= BI_RLE4
&&
431 mBIH
.compression
!= BI_ALPHABITFIELDS
) {
432 // mRow is not used for RLE encoded images
433 mRow
= (uint8_t*)moz_malloc((mBIH
.width
* mBIH
.bpp
) / 8 + 4);
434 // + 4 because the line is padded to a 4 bit boundary, but
435 // I don't want to make exact calculations here, that's unnecessary.
436 // Also, it compensates rounding error.
443 PostDecoderError(NS_ERROR_FAILURE
);
447 // Prepare for transparency
448 if ((mBIH
.compression
== BI_RLE8
) || (mBIH
.compression
== BI_RLE4
)) {
449 // Clear the image, as the RLE may jump over areas
450 memset(mImageData
, 0, mImageDataLength
);
454 if (mColors
&& mPos
>= mLOH
) {
455 // OS/2 Bitmaps have no padding byte
456 uint8_t bytesPerColor
= (mBFH
.bihsize
== OS2_BIH_LENGTH
) ? 3 : 4;
457 if (mPos
< (mLOH
+ mNumColors
* bytesPerColor
)) {
458 // Number of bytes already received
459 uint32_t colorBytes
= mPos
- mLOH
;
460 // Color which is currently received
461 uint8_t colorNum
= colorBytes
/ bytesPerColor
;
462 uint8_t at
= colorBytes
% bytesPerColor
;
463 while (aCount
&& (mPos
< (mLOH
+ mNumColors
* bytesPerColor
))) {
466 mColors
[colorNum
].blue
= *aBuffer
;
469 mColors
[colorNum
].green
= *aBuffer
;
472 mColors
[colorNum
].red
= *aBuffer
;
473 // If there is no padding byte, increment the color index
474 // since we're done with the current color.
475 if (bytesPerColor
== 3) {
480 // This is a padding byte only in Windows BMPs. Increment
481 // the color index since we're done with the current color.
485 mPos
++; aBuffer
++; aCount
--;
486 at
= (at
+ 1) % bytesPerColor
;
489 } else if (aCount
&& mBIH
.compression
== BI_BITFIELDS
&& mPos
<
490 (WIN_V3_HEADER_LENGTH
+ BITFIELD_LENGTH
)) {
491 // If compression is used, this is a windows bitmap (compression
492 // can't be used with OS/2 bitmaps),
493 // hence we can use WIN_V3_HEADER_LENGTH instead of mLOH.
496 // If aCount != 0 then mPos should be >= mLOH due to the if statements
497 // at the beginning of the function
498 MOZ_ASSERT(mPos
>= mLOH
);
499 MOZ_ASSERT(mLOH
== WIN_V3_HEADER_LENGTH
);
501 // mLOH == WIN_V3_HEADER_LENGTH (verified above)
502 // mPos >= mLOH (verified above)
503 // mPos < WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH
505 // So toCopy is in the range
506 // 0 to (BITFIELD_LENGTH - 1)
507 uint32_t toCopy
= (WIN_V3_HEADER_LENGTH
+ BITFIELD_LENGTH
) - mPos
;
508 if (toCopy
> aCount
) {
512 // mPos >= WIN_V3_HEADER_LENGTH
513 // mPos < WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH
515 // offset is in the range
516 // 0 to (BITFIELD_LENGTH - 1)
518 // BITFIELD_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH
519 // and sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH (verified at
522 // Therefore this assert should hold
523 const uint32_t offset
= mPos
- WIN_V3_HEADER_LENGTH
;
524 MOZ_ASSERT(offset
< sizeof(mRawBuf
));
527 // mPos = WIN_V3_HEADER_LENGTH
530 // toCopy = BITFIELD_LENGTH
532 // This will be in the bounds of sizeof(mRawBuf)
536 // mPos = WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH - 1
538 // offset = BITFIELD_LENGTH - 1
541 // This will be in the bounds of sizeof(mRawBuf)
543 // As BITFIELD_LENGTH < WIN_V3_INTERNAL_BIH_LENGTH and
544 // sizeof(mRawBuf) == WIN_V3_INTERNAL_BIH_LENGTH
546 // Therefore this assert should hold
547 MOZ_ASSERT(offset
+ toCopy
<= sizeof(mRawBuf
));
549 memcpy(mRawBuf
+ offset
, aBuffer
, toCopy
);
554 if (mPos
== WIN_V3_HEADER_LENGTH
+ BITFIELD_LENGTH
&&
555 mBIH
.compression
== BI_BITFIELDS
) {
556 mBitFields
.red
= LittleEndian::readUint32(reinterpret_cast<uint32_t*>
558 mBitFields
.green
= LittleEndian::readUint32(reinterpret_cast<uint32_t*>
560 mBitFields
.blue
= LittleEndian::readUint32(reinterpret_cast<uint32_t*>
564 while (aCount
&& (mPos
< mBFH
.dataoffset
)) { // Skip whatever is between
566 mPos
++; aBuffer
++; aCount
--;
568 if (aCount
&& ++mPos
>= mBFH
.dataoffset
) {
569 // Need to increment mPos, else we might get to mPos==mLOH again
570 // From now on, mPos is irrelevant
571 if (!mBIH
.compression
|| mBIH
.compression
== BI_BITFIELDS
) {
572 uint32_t rowSize
= (mBIH
.bpp
* mBIH
.width
+ 7) / 8; // + 7 to
575 rowSize
+= (4 - (rowSize
% 4)); // Pad to DWORD Boundary
579 toCopy
= rowSize
- mRowBytes
;
581 if (toCopy
> aCount
) {
584 memcpy(mRow
+ mRowBytes
, aBuffer
, toCopy
);
589 if (rowSize
== mRowBytes
) {
590 // Collected a whole row into mRow, process it
592 uint32_t* d
= reinterpret_cast<uint32_t*>(mImageData
) +
593 PIXEL_OFFSET(mCurLine
, 0);
594 uint32_t lpos
= mBIH
.width
;
600 for (bit
= 7; bit
>= 0 && lpos
> 0; bit
--) {
601 idx
= (*p
>> bit
) & 1;
602 SetPixel(d
, idx
, mColors
);
610 Set4BitPixel(d
, *p
, lpos
, mColors
);
616 SetPixel(d
, *p
, mColors
);
623 uint16_t val
= LittleEndian::
624 readUint16(reinterpret_cast<uint16_t*>(p
));
626 (val
& mBitFields
.red
) >>
627 mBitFields
.redRightShift
<<
628 mBitFields
.redLeftShift
,
629 (val
& mBitFields
.green
) >>
630 mBitFields
.greenRightShift
<<
631 mBitFields
.greenLeftShift
,
632 (val
& mBitFields
.blue
) >>
633 mBitFields
.blueRightShift
<<
634 mBitFields
.blueLeftShift
);
641 SetPixel(d
, p
[2], p
[1], p
[0]);
650 if (!mHaveAlphaData
&& p
[3]) {
651 // Non-zero alpha byte detected! Clear previous
652 // pixels that we have already processed.
653 // This works because we know that if we
654 // are reaching here then the alpha data in byte
655 // 4 has been right all along. And we know it
656 // has been set to 0 the whole time, so that
657 // means that everything is transparent so far.
658 uint32_t* start
= reinterpret_cast<uint32_t*>
659 (mImageData
) + GetWidth() *
661 uint32_t heightDifference
= GetHeight() -
663 uint32_t pixelCount
= GetWidth() *
666 memset(start
, 0, pixelCount
* sizeof(uint32_t));
668 PostHasTransparency();
669 mHaveAlphaData
= true;
671 SetPixel(d
, p
[2], p
[1], p
[0], mHaveAlphaData
? p
[3] : 0xFF);
673 SetPixel(d
, p
[2], p
[1], p
[0]);
680 NS_NOTREACHED("Unsupported color depth,"
681 " but earlier check didn't catch it");
684 if (mCurLine
== 0) { // Finished last line
689 } while (aCount
> 0);
690 } else if ((mBIH
.compression
== BI_RLE8
) ||
691 (mBIH
.compression
== BI_RLE4
)) {
692 if (((mBIH
.compression
== BI_RLE8
) && (mBIH
.bpp
!= 8)) ||
693 ((mBIH
.compression
== BI_RLE4
) && (mBIH
.bpp
!= 4) &&
695 PR_LOG(GetBMPLog(), PR_LOG_DEBUG
,
696 ("BMP RLE8/RLE4 compression only supports 8/4 bits per"
706 case eRLEStateInitial
:
707 mStateData
= (uint8_t)*aBuffer
++;
710 mState
= eRLEStateNeedSecondEscapeByte
;
713 case eRLEStateNeedSecondEscapeByte
:
716 if (mStateData
!= RLE_ESCAPE
) { // encoded mode
717 // Encoded mode consists of two bytes:
718 // the first byte (mStateData) specifies the
719 // number of consecutive pixels to be drawn
720 // using the color index contained in
722 // Work around bitmaps that specify too many pixels
723 mState
= eRLEStateInitial
;
724 uint32_t pixelsNeeded
= std::min
<uint32_t>(mBIH
.width
- mCurPos
,
727 uint32_t* d
= reinterpret_cast<uint32_t*>
728 (mImageData
) + PIXEL_OFFSET(mCurLine
, mCurPos
);
729 mCurPos
+= pixelsNeeded
;
730 if (mBIH
.compression
== BI_RLE8
) {
732 SetPixel(d
, byte
, mColors
);
734 } while (pixelsNeeded
);
737 Set4BitPixel(d
, byte
, pixelsNeeded
, mColors
);
738 } while (pixelsNeeded
);
746 // End of Line: Go to next row
749 mState
= eRLEStateInitial
;
752 case RLE_ESCAPE_EOF
: // EndOfFile
753 mCurPos
= mCurLine
= 0;
756 case RLE_ESCAPE_DELTA
:
757 mState
= eRLEStateNeedXDelta
;
760 default : // absolute mode
761 // Save the number of pixels to read
763 if (mCurPos
+ mStateData
> (uint32_t)mBIH
.width
) {
764 // We can work around bitmaps that specify
765 // one pixel too many, but only if their
767 mStateData
-= mBIH
.width
& 1;
768 if (mCurPos
+ mStateData
> (uint32_t)mBIH
.width
) {
774 // See if we will need to skip a byte
775 // to word align the pixel data
776 // mStateData is a number of pixels
777 // so allow for the RLE compression type
778 // Pixels RLE8=1 RLE4=2
783 if (((mStateData
- 1) & mBIH
.compression
) != 0) {
784 mState
= eRLEStateAbsoluteMode
;
786 mState
= eRLEStateAbsoluteModePadded
;
792 case eRLEStateNeedXDelta
:
793 // Handle the XDelta and proceed to get Y Delta
797 // Delta encoding makes it possible to skip pixels
798 // making the image transparent.
799 if (MOZ_UNLIKELY(!mHaveAlphaData
)) {
800 PostHasTransparency();
802 mUseAlphaData
= mHaveAlphaData
= true;
803 if (mCurPos
> mBIH
.width
) {
804 mCurPos
= mBIH
.width
;
807 mState
= eRLEStateNeedYDelta
;
810 case eRLEStateNeedYDelta
:
811 // Get the Y Delta and then "handle" the move
814 mState
= eRLEStateInitial
;
815 // Delta encoding makes it possible to skip pixels
816 // making the image transparent.
817 if (MOZ_UNLIKELY(!mHaveAlphaData
)) {
818 PostHasTransparency();
820 mUseAlphaData
= mHaveAlphaData
= true;
821 mCurLine
-= std::min
<int32_t>(byte
, mCurLine
);
824 case eRLEStateAbsoluteMode
: // Absolute Mode
825 case eRLEStateAbsoluteModePadded
:
827 // In absolute mode, the second byte (mStateData)
828 // represents the number of pixels
829 // that follow, each of which contains
830 // the color index of a single pixel.
831 uint32_t* d
= reinterpret_cast<uint32_t*>
833 PIXEL_OFFSET(mCurLine
, mCurPos
);
834 uint32_t* oldPos
= d
;
835 if (mBIH
.compression
== BI_RLE8
) {
836 while (aCount
> 0 && mStateData
> 0) {
839 SetPixel(d
, byte
, mColors
);
843 while (aCount
> 0 && mStateData
> 0) {
846 Set4BitPixel(d
, byte
, mStateData
, mColors
);
849 mCurPos
+= d
- oldPos
;
852 if (mStateData
== 0) {
853 // In absolute mode, each run must
854 // be aligned on a word boundary
856 if (mState
== eRLEStateAbsoluteMode
) {
858 mState
= eRLEStateInitial
;
859 } else if (aCount
> 0) {
861 // "next" byte is just a padding byte
862 // so "move" past it and we can continue
865 mState
= eRLEStateInitial
;
868 // else state is still eRLEStateAbsoluteMode
873 "BMP RLE decompression: unknown state!");
874 PostDecoderError(NS_ERROR_UNEXPECTED
);
877 // Because of the use of the continue statement
878 // we only get here for eol, eof or y delta
880 // Finished last line
887 const uint32_t rows
= mOldLine
- mCurLine
;
890 nsIntRect
r(0, mBIH
.height
< 0 ? -mBIH
.height
- mOldLine
: mCurLine
,
901 nsBMPDecoder::ProcessFileHeader()
903 memset(&mBFH
, 0, sizeof(mBFH
));
904 memcpy(&mBFH
.signature
, mRawBuf
, sizeof(mBFH
.signature
));
905 memcpy(&mBFH
.filesize
, mRawBuf
+ 2, sizeof(mBFH
.filesize
));
906 memcpy(&mBFH
.reserved
, mRawBuf
+ 6, sizeof(mBFH
.reserved
));
907 memcpy(&mBFH
.dataoffset
, mRawBuf
+ 10, sizeof(mBFH
.dataoffset
));
908 memcpy(&mBFH
.bihsize
, mRawBuf
+ 14, sizeof(mBFH
.bihsize
));
910 // Now correct the endianness of the header
911 mBFH
.filesize
= LittleEndian::readUint32(&mBFH
.filesize
);
912 mBFH
.dataoffset
= LittleEndian::readUint32(&mBFH
.dataoffset
);
913 mBFH
.bihsize
= LittleEndian::readUint32(&mBFH
.bihsize
);
917 nsBMPDecoder::ProcessInfoHeader()
919 memset(&mBIH
, 0, sizeof(mBIH
));
920 if (mBFH
.bihsize
== 12) { // OS/2 Bitmap
921 memcpy(&mBIH
.width
, mRawBuf
, 2);
922 memcpy(&mBIH
.height
, mRawBuf
+ 2, 2);
923 memcpy(&mBIH
.planes
, mRawBuf
+ 4, sizeof(mBIH
.planes
));
924 memcpy(&mBIH
.bpp
, mRawBuf
+ 6, sizeof(mBIH
.bpp
));
926 memcpy(&mBIH
.width
, mRawBuf
, sizeof(mBIH
.width
));
927 memcpy(&mBIH
.height
, mRawBuf
+ 4, sizeof(mBIH
.height
));
928 memcpy(&mBIH
.planes
, mRawBuf
+ 8, sizeof(mBIH
.planes
));
929 memcpy(&mBIH
.bpp
, mRawBuf
+ 10, sizeof(mBIH
.bpp
));
930 memcpy(&mBIH
.compression
, mRawBuf
+ 12, sizeof(mBIH
.compression
));
931 memcpy(&mBIH
.image_size
, mRawBuf
+ 16, sizeof(mBIH
.image_size
));
932 memcpy(&mBIH
.xppm
, mRawBuf
+ 20, sizeof(mBIH
.xppm
));
933 memcpy(&mBIH
.yppm
, mRawBuf
+ 24, sizeof(mBIH
.yppm
));
934 memcpy(&mBIH
.colors
, mRawBuf
+ 28, sizeof(mBIH
.colors
));
935 memcpy(&mBIH
.important_colors
, mRawBuf
+ 32,
936 sizeof(mBIH
.important_colors
));
939 // Convert endianness
940 mBIH
.width
= LittleEndian::readUint32(&mBIH
.width
);
941 mBIH
.height
= LittleEndian::readUint32(&mBIH
.height
);
942 mBIH
.planes
= LittleEndian::readUint16(&mBIH
.planes
);
943 mBIH
.bpp
= LittleEndian::readUint16(&mBIH
.bpp
);
945 mBIH
.compression
= LittleEndian::readUint32(&mBIH
.compression
);
946 mBIH
.image_size
= LittleEndian::readUint32(&mBIH
.image_size
);
947 mBIH
.xppm
= LittleEndian::readUint32(&mBIH
.xppm
);
948 mBIH
.yppm
= LittleEndian::readUint32(&mBIH
.yppm
);
949 mBIH
.colors
= LittleEndian::readUint32(&mBIH
.colors
);
950 mBIH
.important_colors
= LittleEndian::readUint32(&mBIH
.important_colors
);
954 } // namespace mozilla