image/decoders/nsBMPDecoder.cpp

branch
TOR_BUG_9701
changeset 10
ac0c01689b40
equal deleted inserted replaced
-1:000000000000 0:f6676fbfa338
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/. */
5 /* I got the format description from http://www.daubnet.com/formats/BMP.html */
6
7 /* This is a Cross-Platform BMP Decoder, which should work everywhere, including
8 * Big-Endian machines like the PowerPC. */
9
10 #include <stdlib.h>
11
12 #include "ImageLogging.h"
13 #include "mozilla/Endian.h"
14 #include "nsBMPDecoder.h"
15
16 #include "nsIInputStream.h"
17 #include "RasterImage.h"
18 #include <algorithm>
19
20 namespace mozilla {
21 namespace image {
22
23 #ifdef PR_LOGGING
24 static PRLogModuleInfo *
25 GetBMPLog()
26 {
27 static PRLogModuleInfo *sBMPLog;
28 if (!sBMPLog)
29 sBMPLog = PR_NewLogModule("BMPDecoder");
30 return sBMPLog;
31 }
32 #endif
33
34 // Convert from row (1..height) to absolute line (0..height-1)
35 #define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
36 #define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
37
38 nsBMPDecoder::nsBMPDecoder(RasterImage &aImage)
39 : Decoder(aImage)
40 {
41 mColors = nullptr;
42 mRow = nullptr;
43 mCurPos = mPos = mNumColors = mRowBytes = 0;
44 mOldLine = mCurLine = 1; // Otherwise decoder will never start
45 mState = eRLEStateInitial;
46 mStateData = 0;
47 mLOH = WIN_V3_HEADER_LENGTH;
48 mUseAlphaData = mHaveAlphaData = false;
49 }
50
51 nsBMPDecoder::~nsBMPDecoder()
52 {
53 delete[] mColors;
54 if (mRow) {
55 moz_free(mRow);
56 }
57 }
58
59 // Sets whether or not the BMP will use alpha data
60 void
61 nsBMPDecoder::SetUseAlphaData(bool useAlphaData)
62 {
63 mUseAlphaData = useAlphaData;
64 }
65
66 // Obtains the bits per pixel from the internal BIH header
67 int32_t
68 nsBMPDecoder::GetBitsPerPixel() const
69 {
70 return mBIH.bpp;
71 }
72
73 // Obtains the width from the internal BIH header
74 int32_t
75 nsBMPDecoder::GetWidth() const
76 {
77 return mBIH.width;
78 }
79
80 // Obtains the abs-value of the height from the internal BIH header
81 int32_t
82 nsBMPDecoder::GetHeight() const
83 {
84 return abs(mBIH.height);
85 }
86
87 // Obtains the internal output image buffer
88 uint32_t*
89 nsBMPDecoder::GetImageData()
90 {
91 return reinterpret_cast<uint32_t*>(mImageData);
92 }
93
94 // Obtains the size of the compressed image resource
95 int32_t
96 nsBMPDecoder::GetCompressedImageSize() const
97 {
98 // For everything except BI_RGB the header field must be defined
99 if (mBIH.compression != BI_RGB) {
100 return mBIH.image_size;
101 }
102
103 // mBIH.image_size isn't always filled for BI_RGB so calculate it manually
104 // The pixel array size is calculated based on extra 4 byte boundary padding
105 uint32_t rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
106 // Pad to DWORD Boundary
107 if (rowSize % 4) {
108 rowSize += (4 - (rowSize % 4));
109 }
110
111 // The height should be the absolute value of what the height is in the BIH.
112 // If positive the bitmap is stored bottom to top, otherwise top to bottom
113 int32_t pixelArraySize = rowSize * GetHeight();
114 return pixelArraySize;
115 }
116
117 // Obtains whether or not a BMP file had alpha data in its 4th byte
118 // for 32BPP bitmaps. Only use after the bitmap has been processed.
119 bool
120 nsBMPDecoder::HasAlphaData() const
121 {
122 return mHaveAlphaData;
123 }
124
125
126 void
127 nsBMPDecoder::FinishInternal()
128 {
129 // We shouldn't be called in error cases
130 NS_ABORT_IF_FALSE(!HasError(), "Can't call FinishInternal on error!");
131
132 // We should never make multiple frames
133 NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple BMP frames?");
134
135 // Send notifications if appropriate
136 if (!IsSizeDecode() && HasSize()) {
137
138 // Invalidate
139 nsIntRect r(0, 0, mBIH.width, GetHeight());
140 PostInvalidation(r);
141
142 if (mUseAlphaData) {
143 PostFrameStop(FrameBlender::kFrameHasAlpha);
144 } else {
145 PostFrameStop(FrameBlender::kFrameOpaque);
146 }
147 PostDecodeDone();
148 }
149 }
150
151 // ----------------------------------------
152 // Actual Data Processing
153 // ----------------------------------------
154
155 static void calcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength)
156 {
157 // find the rightmost 1
158 uint8_t pos;
159 bool started = false;
160 aBegin = aLength = 0;
161 for (pos = 0; pos <= 31; pos++) {
162 if (!started && (aMask & (1 << pos))) {
163 aBegin = pos;
164 started = true;
165 }
166 else if (started && !(aMask & (1 << pos))) {
167 aLength = pos - aBegin;
168 break;
169 }
170 }
171 }
172
173 NS_METHOD nsBMPDecoder::CalcBitShift()
174 {
175 uint8_t begin, length;
176 // red
177 calcBitmask(mBitFields.red, begin, length);
178 mBitFields.redRightShift = begin;
179 mBitFields.redLeftShift = 8 - length;
180 // green
181 calcBitmask(mBitFields.green, begin, length);
182 mBitFields.greenRightShift = begin;
183 mBitFields.greenLeftShift = 8 - length;
184 // blue
185 calcBitmask(mBitFields.blue, begin, length);
186 mBitFields.blueRightShift = begin;
187 mBitFields.blueLeftShift = 8 - length;
188 return NS_OK;
189 }
190
191 void
192 nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy)
193 {
194 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
195
196 // aCount=0 means EOF, mCurLine=0 means we're past end of image
197 if (!aCount || !mCurLine)
198 return;
199
200 if (mPos < BFH_INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
201 uint32_t toCopy = BFH_INTERNAL_LENGTH - mPos;
202 if (toCopy > aCount)
203 toCopy = aCount;
204 memcpy(mRawBuf + mPos, aBuffer, toCopy);
205 mPos += toCopy;
206 aCount -= toCopy;
207 aBuffer += toCopy;
208 }
209 if (mPos == BFH_INTERNAL_LENGTH) {
210 ProcessFileHeader();
211 if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
212 PostDataError();
213 return;
214 }
215 if (mBFH.bihsize == OS2_BIH_LENGTH)
216 mLOH = OS2_HEADER_LENGTH;
217 }
218 if (mPos >= BFH_INTERNAL_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
219 uint32_t toCopy = mLOH - mPos;
220 if (toCopy > aCount)
221 toCopy = aCount;
222 memcpy(mRawBuf + (mPos - BFH_INTERNAL_LENGTH), aBuffer, toCopy);
223 mPos += toCopy;
224 aCount -= toCopy;
225 aBuffer += toCopy;
226 }
227
228 // HasSize is called to ensure that if at this point mPos == mLOH but
229 // we have no data left to process, the next time WriteInternal is called
230 // we won't enter this condition again.
231 if (mPos == mLOH && !HasSize()) {
232 ProcessInfoHeader();
233 PR_LOG(GetBMPLog(), PR_LOG_DEBUG, ("BMP is %lix%lix%lu. compression=%lu\n",
234 mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
235 // Verify we support this bit depth
236 if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
237 mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
238 PostDataError();
239 return;
240 }
241
242 // BMPs with negative width are invalid
243 // Reject extremely wide images to keep the math sane
244 const int32_t k64KWidth = 0x0000FFFF;
245 if (mBIH.width < 0 || mBIH.width > k64KWidth) {
246 PostDataError();
247 return;
248 }
249
250 if (mBIH.height == INT_MIN) {
251 PostDataError();
252 return;
253 }
254
255 uint32_t real_height = GetHeight();
256
257 // Post our size to the superclass
258 PostSize(mBIH.width, real_height);
259 if (HasError()) {
260 // Setting the size led to an error.
261 return;
262 }
263
264 // We have the size. If we're doing a size decode, we got what
265 // we came for.
266 if (IsSizeDecode())
267 return;
268
269 // We're doing a real decode.
270 mOldLine = mCurLine = real_height;
271
272 if (mBIH.bpp <= 8) {
273 mNumColors = 1 << mBIH.bpp;
274 if (mBIH.colors && mBIH.colors < mNumColors)
275 mNumColors = mBIH.colors;
276
277 // Always allocate 256 even though mNumColors might be smaller
278 mColors = new colorTable[256];
279 memset(mColors, 0, 256 * sizeof(colorTable));
280 }
281 else if (mBIH.compression != BI_BITFIELDS && mBIH.bpp == 16) {
282 // Use default 5-5-5 format
283 mBitFields.red = 0x7C00;
284 mBitFields.green = 0x03E0;
285 mBitFields.blue = 0x001F;
286 CalcBitShift();
287 }
288
289 // Make sure we have a valid value for our supported compression modes
290 // before adding the frame
291 if (mBIH.compression != BI_RGB && mBIH.compression != BI_RLE8 &&
292 mBIH.compression != BI_RLE4 && mBIH.compression != BI_BITFIELDS) {
293 PostDataError();
294 return;
295 }
296
297 // If we have RLE4 or RLE8 or BI_ALPHABITFIELDS, then ensure we
298 // have valid BPP values before adding the frame
299 if (mBIH.compression == BI_RLE8 && mBIH.bpp != 8) {
300 PR_LOG(GetBMPLog(), PR_LOG_DEBUG,
301 ("BMP RLE8 compression only supports 8 bits per pixel\n"));
302 PostDataError();
303 return;
304 }
305 if (mBIH.compression == BI_RLE4 && mBIH.bpp != 4 && mBIH.bpp != 1) {
306 PR_LOG(GetBMPLog(), PR_LOG_DEBUG,
307 ("BMP RLE4 compression only supports 4 bits per pixel\n"));
308 PostDataError();
309 return;
310 }
311 if (mBIH.compression == BI_ALPHABITFIELDS &&
312 mBIH.bpp != 16 && mBIH.bpp != 32) {
313 PR_LOG(GetBMPLog(), PR_LOG_DEBUG,
314 ("BMP ALPHABITFIELDS only supports 16 or 32 bits per pixel\n"));
315 PostDataError();
316 return;
317 }
318
319 if (mBIH.compression != BI_RLE8 && mBIH.compression != BI_RLE4 &&
320 mBIH.compression != BI_ALPHABITFIELDS) {
321 // mRow is not used for RLE encoded images
322 mRow = (uint8_t*)moz_malloc((mBIH.width * mBIH.bpp) / 8 + 4);
323 // + 4 because the line is padded to a 4 bit boundary, but I don't want
324 // to make exact calculations here, that's unnecessary.
325 // Also, it compensates rounding error.
326 if (!mRow) {
327 PostDataError();
328 return;
329 }
330 }
331 if (!mImageData) {
332 PostDecoderError(NS_ERROR_FAILURE);
333 return;
334 }
335
336 // Prepare for transparency
337 if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
338 // Clear the image, as the RLE may jump over areas
339 memset(mImageData, 0, mImageDataLength);
340 }
341 }
342
343 if (mColors && mPos >= mLOH) {
344 // OS/2 Bitmaps have no padding byte
345 uint8_t bytesPerColor = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4;
346 if (mPos < (mLOH + mNumColors * bytesPerColor)) {
347 // Number of bytes already received
348 uint32_t colorBytes = mPos - mLOH;
349 // Color which is currently received
350 uint8_t colorNum = colorBytes / bytesPerColor;
351 uint8_t at = colorBytes % bytesPerColor;
352 while (aCount && (mPos < (mLOH + mNumColors * bytesPerColor))) {
353 switch (at) {
354 case 0:
355 mColors[colorNum].blue = *aBuffer;
356 break;
357 case 1:
358 mColors[colorNum].green = *aBuffer;
359 break;
360 case 2:
361 mColors[colorNum].red = *aBuffer;
362 // If there is no padding byte, increment the color index
363 // since we're done with the current color.
364 if (bytesPerColor == 3)
365 colorNum++;
366 break;
367 case 3:
368 // This is a padding byte only in Windows BMPs. Increment
369 // the color index since we're done with the current color.
370 colorNum++;
371 break;
372 }
373 mPos++; aBuffer++; aCount--;
374 at = (at + 1) % bytesPerColor;
375 }
376 }
377 }
378 else if (aCount && mBIH.compression == BI_BITFIELDS && mPos < (WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH)) {
379 // If compression is used, this is a windows bitmap, hence we can
380 // use WIN_HEADER_LENGTH instead of mLOH
381 uint32_t toCopy = (WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH) - mPos;
382 if (toCopy > aCount)
383 toCopy = aCount;
384 memcpy(mRawBuf + (mPos - WIN_V3_HEADER_LENGTH), aBuffer, toCopy);
385 mPos += toCopy;
386 aBuffer += toCopy;
387 aCount -= toCopy;
388 }
389 if (mPos == WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH &&
390 mBIH.compression == BI_BITFIELDS) {
391 mBitFields.red = LittleEndian::readUint32(reinterpret_cast<uint32_t*>(mRawBuf));
392 mBitFields.green = LittleEndian::readUint32(reinterpret_cast<uint32_t*>(mRawBuf + 4));
393 mBitFields.blue = LittleEndian::readUint32(reinterpret_cast<uint32_t*>(mRawBuf + 8));
394 CalcBitShift();
395 }
396 while (aCount && (mPos < mBFH.dataoffset)) { // Skip whatever is between header and data
397 mPos++; aBuffer++; aCount--;
398 }
399 if (aCount && ++mPos >= mBFH.dataoffset) {
400 // Need to increment mPos, else we might get to mPos==mLOH again
401 // From now on, mPos is irrelevant
402 if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
403 uint32_t rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
404 if (rowSize % 4) {
405 rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
406 }
407 uint32_t toCopy;
408 do {
409 toCopy = rowSize - mRowBytes;
410 if (toCopy) {
411 if (toCopy > aCount)
412 toCopy = aCount;
413 memcpy(mRow + mRowBytes, aBuffer, toCopy);
414 aCount -= toCopy;
415 aBuffer += toCopy;
416 mRowBytes += toCopy;
417 }
418 if (rowSize == mRowBytes) {
419 // Collected a whole row into mRow, process it
420 uint8_t* p = mRow;
421 uint32_t* d = reinterpret_cast<uint32_t*>(mImageData) + PIXEL_OFFSET(mCurLine, 0);
422 uint32_t lpos = mBIH.width;
423 switch (mBIH.bpp) {
424 case 1:
425 while (lpos > 0) {
426 int8_t bit;
427 uint8_t idx;
428 for (bit = 7; bit >= 0 && lpos > 0; bit--) {
429 idx = (*p >> bit) & 1;
430 SetPixel(d, idx, mColors);
431 --lpos;
432 }
433 ++p;
434 }
435 break;
436 case 4:
437 while (lpos > 0) {
438 Set4BitPixel(d, *p, lpos, mColors);
439 ++p;
440 }
441 break;
442 case 8:
443 while (lpos > 0) {
444 SetPixel(d, *p, mColors);
445 --lpos;
446 ++p;
447 }
448 break;
449 case 16:
450 while (lpos > 0) {
451 uint16_t val = LittleEndian::readUint16(reinterpret_cast<uint16_t*>(p));
452 SetPixel(d,
453 (val & mBitFields.red) >> mBitFields.redRightShift << mBitFields.redLeftShift,
454 (val & mBitFields.green) >> mBitFields.greenRightShift << mBitFields.greenLeftShift,
455 (val & mBitFields.blue) >> mBitFields.blueRightShift << mBitFields.blueLeftShift);
456 --lpos;
457 p+=2;
458 }
459 break;
460 case 24:
461 while (lpos > 0) {
462 SetPixel(d, p[2], p[1], p[0]);
463 p += 2;
464 --lpos;
465 ++p;
466 }
467 break;
468 case 32:
469 while (lpos > 0) {
470 if (mUseAlphaData) {
471 if (!mHaveAlphaData && p[3]) {
472 // Non-zero alpha byte detected! Clear previous
473 // pixels that we have already processed.
474 // This works because we know that if we
475 // are reaching here then the alpha data in byte
476 // 4 has been right all along. And we know it
477 // has been set to 0 the whole time, so that
478 // means that everything is transparent so far.
479 uint32_t* start = reinterpret_cast<uint32_t*>(mImageData) + GetWidth() * (mCurLine - 1);
480 uint32_t heightDifference = GetHeight() - mCurLine + 1;
481 uint32_t pixelCount = GetWidth() * heightDifference;
482
483 memset(start, 0, pixelCount * sizeof(uint32_t));
484
485 mHaveAlphaData = true;
486 }
487 SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ? p[3] : 0xFF);
488 } else {
489 SetPixel(d, p[2], p[1], p[0]);
490 }
491 p += 4;
492 --lpos;
493 }
494 break;
495 default:
496 NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
497 }
498 mCurLine --;
499 if (mCurLine == 0) { // Finished last line
500 break;
501 }
502 mRowBytes = 0;
503
504 }
505 } while (aCount > 0);
506 }
507 else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
508 if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) ||
509 ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
510 PR_LOG(GetBMPLog(), PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
511 PostDataError();
512 return;
513 }
514
515 while (aCount > 0) {
516 uint8_t byte;
517
518 switch(mState) {
519 case eRLEStateInitial:
520 mStateData = (uint8_t)*aBuffer++;
521 aCount--;
522
523 mState = eRLEStateNeedSecondEscapeByte;
524 continue;
525
526 case eRLEStateNeedSecondEscapeByte:
527 byte = *aBuffer++;
528 aCount--;
529 if (mStateData != RLE_ESCAPE) { // encoded mode
530 // Encoded mode consists of two bytes:
531 // the first byte (mStateData) specifies the
532 // number of consecutive pixels to be drawn
533 // using the color index contained in
534 // the second byte
535 // Work around bitmaps that specify too many pixels
536 mState = eRLEStateInitial;
537 uint32_t pixelsNeeded = std::min<uint32_t>(mBIH.width - mCurPos, mStateData);
538 if (pixelsNeeded) {
539 uint32_t* d = reinterpret_cast<uint32_t*>(mImageData) + PIXEL_OFFSET(mCurLine, mCurPos);
540 mCurPos += pixelsNeeded;
541 if (mBIH.compression == BI_RLE8) {
542 do {
543 SetPixel(d, byte, mColors);
544 pixelsNeeded --;
545 } while (pixelsNeeded);
546 } else {
547 do {
548 Set4BitPixel(d, byte, pixelsNeeded, mColors);
549 } while (pixelsNeeded);
550 }
551 }
552 continue;
553 }
554
555 switch(byte) {
556 case RLE_ESCAPE_EOL:
557 // End of Line: Go to next row
558 mCurLine --;
559 mCurPos = 0;
560 mState = eRLEStateInitial;
561 break;
562
563 case RLE_ESCAPE_EOF: // EndOfFile
564 mCurPos = mCurLine = 0;
565 break;
566
567 case RLE_ESCAPE_DELTA:
568 mState = eRLEStateNeedXDelta;
569 continue;
570
571 default : // absolute mode
572 // Save the number of pixels to read
573 mStateData = byte;
574 if (mCurPos + mStateData > (uint32_t)mBIH.width) {
575 // We can work around bitmaps that specify one
576 // pixel too many, but only if their width is odd.
577 mStateData -= mBIH.width & 1;
578 if (mCurPos + mStateData > (uint32_t)mBIH.width) {
579 PostDataError();
580 return;
581 }
582 }
583
584 // See if we will need to skip a byte
585 // to word align the pixel data
586 // mStateData is a number of pixels
587 // so allow for the RLE compression type
588 // Pixels RLE8=1 RLE4=2
589 // 1 Pad Pad
590 // 2 No Pad
591 // 3 Pad No
592 // 4 No No
593 if (((mStateData - 1) & mBIH.compression) != 0)
594 mState = eRLEStateAbsoluteMode;
595 else
596 mState = eRLEStateAbsoluteModePadded;
597 continue;
598 }
599 break;
600
601 case eRLEStateNeedXDelta:
602 // Handle the XDelta and proceed to get Y Delta
603 byte = *aBuffer++;
604 aCount--;
605 mCurPos += byte;
606 if (mCurPos > mBIH.width)
607 mCurPos = mBIH.width;
608
609 mState = eRLEStateNeedYDelta;
610 continue;
611
612 case eRLEStateNeedYDelta:
613 // Get the Y Delta and then "handle" the move
614 byte = *aBuffer++;
615 aCount--;
616 mState = eRLEStateInitial;
617 mCurLine -= std::min<int32_t>(byte, mCurLine);
618 break;
619
620 case eRLEStateAbsoluteMode: // Absolute Mode
621 case eRLEStateAbsoluteModePadded:
622 if (mStateData) {
623 // In absolute mode, the second byte (mStateData)
624 // represents the number of pixels
625 // that follow, each of which contains
626 // the color index of a single pixel.
627 uint32_t* d = reinterpret_cast<uint32_t*>(mImageData) + PIXEL_OFFSET(mCurLine, mCurPos);
628 uint32_t* oldPos = d;
629 if (mBIH.compression == BI_RLE8) {
630 while (aCount > 0 && mStateData > 0) {
631 byte = *aBuffer++;
632 aCount--;
633 SetPixel(d, byte, mColors);
634 mStateData--;
635 }
636 } else {
637 while (aCount > 0 && mStateData > 0) {
638 byte = *aBuffer++;
639 aCount--;
640 Set4BitPixel(d, byte, mStateData, mColors);
641 }
642 }
643 mCurPos += d - oldPos;
644 }
645
646 if (mStateData == 0) {
647 // In absolute mode, each run must
648 // be aligned on a word boundary
649
650 if (mState == eRLEStateAbsoluteMode) { // Word Aligned
651 mState = eRLEStateInitial;
652 } else if (aCount > 0) { // Not word Aligned
653 // "next" byte is just a padding byte
654 // so "move" past it and we can continue
655 aBuffer++;
656 aCount--;
657 mState = eRLEStateInitial;
658 }
659 }
660 // else state is still eRLEStateAbsoluteMode
661 continue;
662
663 default :
664 NS_ABORT_IF_FALSE(0, "BMP RLE decompression: unknown state!");
665 PostDecoderError(NS_ERROR_UNEXPECTED);
666 return;
667 }
668 // Because of the use of the continue statement
669 // we only get here for eol, eof or y delta
670 if (mCurLine == 0) { // Finished last line
671 break;
672 }
673 }
674 }
675 }
676
677 const uint32_t rows = mOldLine - mCurLine;
678 if (rows) {
679
680 // Invalidate
681 nsIntRect r(0, mBIH.height < 0 ? -mBIH.height - mOldLine : mCurLine,
682 mBIH.width, rows);
683 PostInvalidation(r);
684
685 mOldLine = mCurLine;
686 }
687
688 return;
689 }
690
691 void nsBMPDecoder::ProcessFileHeader()
692 {
693 memset(&mBFH, 0, sizeof(mBFH));
694 memcpy(&mBFH.signature, mRawBuf, sizeof(mBFH.signature));
695 memcpy(&mBFH.filesize, mRawBuf + 2, sizeof(mBFH.filesize));
696 memcpy(&mBFH.reserved, mRawBuf + 6, sizeof(mBFH.reserved));
697 memcpy(&mBFH.dataoffset, mRawBuf + 10, sizeof(mBFH.dataoffset));
698 memcpy(&mBFH.bihsize, mRawBuf + 14, sizeof(mBFH.bihsize));
699
700 // Now correct the endianness of the header
701 mBFH.filesize = LittleEndian::readUint32(&mBFH.filesize);
702 mBFH.dataoffset = LittleEndian::readUint32(&mBFH.dataoffset);
703 mBFH.bihsize = LittleEndian::readUint32(&mBFH.bihsize);
704 }
705
706 void nsBMPDecoder::ProcessInfoHeader()
707 {
708 memset(&mBIH, 0, sizeof(mBIH));
709 if (mBFH.bihsize == 12) { // OS/2 Bitmap
710 memcpy(&mBIH.width, mRawBuf, 2);
711 memcpy(&mBIH.height, mRawBuf + 2, 2);
712 memcpy(&mBIH.planes, mRawBuf + 4, sizeof(mBIH.planes));
713 memcpy(&mBIH.bpp, mRawBuf + 6, sizeof(mBIH.bpp));
714 }
715 else {
716 memcpy(&mBIH.width, mRawBuf, sizeof(mBIH.width));
717 memcpy(&mBIH.height, mRawBuf + 4, sizeof(mBIH.height));
718 memcpy(&mBIH.planes, mRawBuf + 8, sizeof(mBIH.planes));
719 memcpy(&mBIH.bpp, mRawBuf + 10, sizeof(mBIH.bpp));
720 memcpy(&mBIH.compression, mRawBuf + 12, sizeof(mBIH.compression));
721 memcpy(&mBIH.image_size, mRawBuf + 16, sizeof(mBIH.image_size));
722 memcpy(&mBIH.xppm, mRawBuf + 20, sizeof(mBIH.xppm));
723 memcpy(&mBIH.yppm, mRawBuf + 24, sizeof(mBIH.yppm));
724 memcpy(&mBIH.colors, mRawBuf + 28, sizeof(mBIH.colors));
725 memcpy(&mBIH.important_colors, mRawBuf + 32, sizeof(mBIH.important_colors));
726 }
727
728 // Convert endianness
729 mBIH.width = LittleEndian::readUint32(&mBIH.width);
730 mBIH.height = LittleEndian::readUint32(&mBIH.height);
731 mBIH.planes = LittleEndian::readUint16(&mBIH.planes);
732 mBIH.bpp = LittleEndian::readUint16(&mBIH.bpp);
733
734 mBIH.compression = LittleEndian::readUint32(&mBIH.compression);
735 mBIH.image_size = LittleEndian::readUint32(&mBIH.image_size);
736 mBIH.xppm = LittleEndian::readUint32(&mBIH.xppm);
737 mBIH.yppm = LittleEndian::readUint32(&mBIH.yppm);
738 mBIH.colors = LittleEndian::readUint32(&mBIH.colors);
739 mBIH.important_colors = LittleEndian::readUint32(&mBIH.important_colors);
740 }
741
742 } // namespace image
743 } // namespace mozilla

mercurial