Line data Source code
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 : // OS/2 VERSIONS OF THE BMP FORMAT
70 : // -------------------------------
71 : // OS2-BMPv1.
72 : // - Almost identical to WinBMPv2; the differences are basically ignorable.
73 : //
74 : // OS2-BMPv2.
75 : // - Similar to WinBMPv3.
76 : // - The info header is 64 bytes but can be reduced to as little as 16; any
77 : // omitted fields are treated as zero. The first 40 bytes of these fields are
78 : // nearly identical to the WinBMPv3 info header; the remaining 24 bytes are
79 : // different.
80 : // - Also adds compression types "Huffman 1D" and "RLE24", which we don't
81 : // support.
82 : // - We treat OS2-BMPv2 files as if they are WinBMPv3 (i.e. ignore the extra 24
83 : // bytes in the info header), which in practice is good enough.
84 :
85 : #include "ImageLogging.h"
86 : #include "nsBMPDecoder.h"
87 :
88 : #include <stdlib.h>
89 :
90 : #include "mozilla/Attributes.h"
91 : #include "mozilla/EndianUtils.h"
92 : #include "mozilla/Likely.h"
93 :
94 : #include "nsIInputStream.h"
95 : #include "RasterImage.h"
96 : #include <algorithm>
97 :
98 : using namespace mozilla::gfx;
99 :
100 : namespace mozilla {
101 : namespace image {
102 : namespace bmp {
103 :
104 : struct Compression {
105 : enum {
106 : RGB = 0,
107 : RLE8 = 1,
108 : RLE4 = 2,
109 : BITFIELDS = 3
110 : };
111 : };
112 :
113 : // RLE escape codes and constants.
114 : struct RLE {
115 : enum {
116 : ESCAPE = 0,
117 : ESCAPE_EOL = 0,
118 : ESCAPE_EOF = 1,
119 : ESCAPE_DELTA = 2,
120 :
121 : SEGMENT_LENGTH = 2,
122 : DELTA_LENGTH = 2
123 : };
124 : };
125 :
126 : } // namespace bmp
127 :
128 : using namespace bmp;
129 :
130 : /// Sets the pixel data in aDecoded to the given values.
131 : /// @param aDecoded pointer to pixel to be set, will be incremented to point to
132 : /// the next pixel.
133 : static void
134 0 : SetPixel(uint32_t*& aDecoded, uint8_t aRed, uint8_t aGreen,
135 : uint8_t aBlue, uint8_t aAlpha = 0xFF)
136 : {
137 0 : *aDecoded++ = gfxPackedPixel(aAlpha, aRed, aGreen, aBlue);
138 0 : }
139 :
140 : static void
141 0 : SetPixel(uint32_t*& aDecoded, uint8_t idx,
142 : const UniquePtr<ColorTableEntry[]>& aColors)
143 : {
144 0 : SetPixel(aDecoded,
145 0 : aColors[idx].mRed, aColors[idx].mGreen, aColors[idx].mBlue);
146 0 : }
147 :
148 : /// Sets two (or one if aCount = 1) pixels
149 : /// @param aDecoded where the data is stored. Will be moved 4 resp 8 bytes
150 : /// depending on whether one or two pixels are written.
151 : /// @param aData The values for the two pixels
152 : /// @param aCount Current count. Is decremented by one or two.
153 : static void
154 0 : Set4BitPixel(uint32_t*& aDecoded, uint8_t aData, uint32_t& aCount,
155 : const UniquePtr<ColorTableEntry[]>& aColors)
156 : {
157 0 : uint8_t idx = aData >> 4;
158 0 : SetPixel(aDecoded, idx, aColors);
159 0 : if (--aCount > 0) {
160 0 : idx = aData & 0xF;
161 0 : SetPixel(aDecoded, idx, aColors);
162 0 : --aCount;
163 : }
164 0 : }
165 :
166 : static mozilla::LazyLogModule sBMPLog("BMPDecoder");
167 :
168 : // The length of the mBIHSize field in the info header.
169 : static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
170 :
171 0 : nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength)
172 : : Decoder(aImage)
173 0 : , mLexer(Transition::To(aState, aLength), Transition::TerminateSuccess())
174 : , mIsWithinICO(false)
175 : , mMayHaveTransparency(false)
176 : , mDoesHaveTransparency(false)
177 : , mNumColors(0)
178 : , mColors(nullptr)
179 : , mBytesPerColor(0)
180 : , mPreGapLength(0)
181 : , mPixelRowSize(0)
182 : , mCurrentRow(0)
183 : , mCurrentPos(0)
184 0 : , mAbsoluteModeNumPixels(0)
185 : {
186 0 : }
187 :
188 : // Constructor for normal BMP files.
189 0 : nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
190 0 : : nsBMPDecoder(aImage, State::FILE_HEADER, FILE_HEADER_LENGTH)
191 : {
192 0 : }
193 :
194 : // Constructor used for WinBMPv3-ICO files, which lack a file header.
195 0 : nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset)
196 0 : : nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH)
197 : {
198 0 : SetIsWithinICO();
199 :
200 : // Even though the file header isn't present in this case, the dataOffset
201 : // field is set as if it is, and so we must increment mPreGapLength
202 : // accordingly.
203 0 : mPreGapLength += FILE_HEADER_LENGTH;
204 :
205 : // This is the one piece of data we normally get from a BMP file header, so
206 : // it must be provided via an argument.
207 0 : mH.mDataOffset = aDataOffset;
208 0 : }
209 :
210 0 : nsBMPDecoder::~nsBMPDecoder()
211 : {
212 0 : }
213 :
214 : // Obtains the size of the compressed image resource.
215 : int32_t
216 0 : nsBMPDecoder::GetCompressedImageSize() const
217 : {
218 : // In the RGB case mImageSize might not be set, so compute it manually.
219 0 : MOZ_ASSERT(mPixelRowSize != 0);
220 0 : return mH.mCompression == Compression::RGB
221 0 : ? mPixelRowSize * AbsoluteHeight()
222 0 : : mH.mImageSize;
223 : }
224 :
225 : nsresult
226 0 : nsBMPDecoder::BeforeFinishInternal()
227 : {
228 0 : if (!IsMetadataDecode() && !mImageData) {
229 0 : return NS_ERROR_FAILURE; // No image; something went wrong.
230 : }
231 :
232 0 : return NS_OK;
233 : }
234 :
235 : nsresult
236 0 : nsBMPDecoder::FinishInternal()
237 : {
238 : // We shouldn't be called in error cases.
239 0 : MOZ_ASSERT(!HasError(), "Can't call FinishInternal on error!");
240 :
241 : // We should never make multiple frames.
242 0 : MOZ_ASSERT(GetFrameCount() <= 1, "Multiple BMP frames?");
243 :
244 : // Send notifications if appropriate.
245 0 : if (!IsMetadataDecode() && HasSize()) {
246 :
247 : // We should have image data.
248 0 : MOZ_ASSERT(mImageData);
249 :
250 : // If it was truncated, fill in the missing pixels as black.
251 0 : while (mCurrentRow > 0) {
252 0 : uint32_t* dst = RowBuffer();
253 0 : while (mCurrentPos < mH.mWidth) {
254 0 : SetPixel(dst, 0, 0, 0);
255 0 : mCurrentPos++;
256 : }
257 0 : mCurrentPos = 0;
258 0 : FinishRow();
259 : }
260 :
261 : // Invalidate.
262 0 : nsIntRect r(0, 0, mH.mWidth, AbsoluteHeight());
263 0 : PostInvalidation(r);
264 :
265 0 : MOZ_ASSERT_IF(mDoesHaveTransparency, mMayHaveTransparency);
266 :
267 : // We have transparency if we either detected some in the image itself
268 : // (i.e., |mDoesHaveTransparency| is true) or we're in an ICO, which could
269 : // mean we have an AND mask that provides transparency (i.e., |mIsWithinICO|
270 : // is true).
271 : // XXX(seth): We can tell when we create the decoder if the AND mask is
272 : // present, so we could be more precise about this.
273 0 : const Opacity opacity = mDoesHaveTransparency || mIsWithinICO
274 0 : ? Opacity::SOME_TRANSPARENCY
275 0 : : Opacity::FULLY_OPAQUE;
276 :
277 0 : PostFrameStop(opacity);
278 0 : PostDecodeDone();
279 : }
280 :
281 0 : return NS_OK;
282 : }
283 :
284 : // ----------------------------------------
285 : // Actual Data Processing
286 : // ----------------------------------------
287 :
288 : void
289 0 : BitFields::Value::Set(uint32_t aMask)
290 : {
291 0 : mMask = aMask;
292 :
293 : // Handle this exceptional case first. The chosen values don't matter
294 : // (because a mask of zero will always give a value of zero) except that
295 : // mBitWidth:
296 : // - shouldn't be zero, because that would cause an infinite loop in Get();
297 : // - shouldn't be 5 or 8, because that could cause a false positive match in
298 : // IsR5G5B5() or IsR8G8B8().
299 0 : if (mMask == 0x0) {
300 0 : mRightShift = 0;
301 0 : mBitWidth = 1;
302 0 : return;
303 : }
304 :
305 : // Find the rightmost 1.
306 : uint8_t i;
307 0 : for (i = 0; i < 32; i++) {
308 0 : if (mMask & (1 << i)) {
309 0 : break;
310 : }
311 : }
312 0 : mRightShift = i;
313 :
314 : // Now find the leftmost 1 in the same run of 1s. (If there are multiple runs
315 : // of 1s -- which isn't valid -- we'll behave as if only the lowest run was
316 : // present, which seems reasonable.)
317 0 : for (i = i + 1; i < 32; i++) {
318 0 : if (!(mMask & (1 << i))) {
319 0 : break;
320 : }
321 : }
322 0 : mBitWidth = i - mRightShift;
323 : }
324 :
325 : MOZ_ALWAYS_INLINE uint8_t
326 0 : BitFields::Value::Get(uint32_t aValue) const
327 : {
328 : // Extract the unscaled value.
329 0 : uint32_t v = (aValue & mMask) >> mRightShift;
330 :
331 : // Idea: to upscale v precisely we need to duplicate its bits, possibly
332 : // repeatedly, possibly partially in the last case, from bit 7 down to bit 0
333 : // in v2. For example:
334 : //
335 : // - mBitWidth=1: v2 = v<<7 | v<<6 | ... | v<<1 | v>>0 k -> kkkkkkkk
336 : // - mBitWidth=2: v2 = v<<6 | v<<4 | v<<2 | v>>0 jk -> jkjkjkjk
337 : // - mBitWidth=3: v2 = v<<5 | v<<2 | v>>1 ijk -> ijkijkij
338 : // - mBitWidth=4: v2 = v<<4 | v>>0 hijk -> hijkhijk
339 : // - mBitWidth=5: v2 = v<<3 | v>>2 ghijk -> ghijkghi
340 : // - mBitWidth=6: v2 = v<<2 | v>>4 fghijk -> fghijkfg
341 : // - mBitWidth=7: v2 = v<<1 | v>>6 efghijk -> efghijke
342 : // - mBitWidth=8: v2 = v>>0 defghijk -> defghijk
343 : // - mBitWidth=9: v2 = v>>1 cdefghijk -> cdefghij
344 : // - mBitWidth=10: v2 = v>>2 bcdefghijk -> bcdefghi
345 : // - mBitWidth=11: v2 = v>>3 abcdefghijk -> abcdefgh
346 : // - etc.
347 : //
348 0 : uint8_t v2 = 0;
349 : int32_t i; // must be a signed integer
350 0 : for (i = 8 - mBitWidth; i > 0; i -= mBitWidth) {
351 0 : v2 |= v << uint32_t(i);
352 : }
353 0 : v2 |= v >> uint32_t(-i);
354 0 : return v2;
355 : }
356 :
357 : MOZ_ALWAYS_INLINE uint8_t
358 0 : BitFields::Value::GetAlpha(uint32_t aValue, bool& aHasAlphaOut) const
359 : {
360 0 : if (mMask == 0x0) {
361 0 : return 0xff;
362 : }
363 0 : aHasAlphaOut = true;
364 0 : return Get(aValue);
365 : }
366 :
367 : MOZ_ALWAYS_INLINE uint8_t
368 0 : BitFields::Value::Get5(uint32_t aValue) const
369 : {
370 0 : MOZ_ASSERT(mBitWidth == 5);
371 0 : uint32_t v = (aValue & mMask) >> mRightShift;
372 0 : return (v << 3u) | (v >> 2u);
373 : }
374 :
375 : MOZ_ALWAYS_INLINE uint8_t
376 0 : BitFields::Value::Get8(uint32_t aValue) const
377 : {
378 0 : MOZ_ASSERT(mBitWidth == 8);
379 0 : uint32_t v = (aValue & mMask) >> mRightShift;
380 0 : return v;
381 : }
382 :
383 : void
384 0 : BitFields::SetR5G5B5()
385 : {
386 0 : mRed.Set(0x7c00);
387 0 : mGreen.Set(0x03e0);
388 0 : mBlue.Set(0x001f);
389 0 : }
390 :
391 : void
392 0 : BitFields::SetR8G8B8()
393 : {
394 0 : mRed.Set(0xff0000);
395 0 : mGreen.Set(0xff00);
396 0 : mBlue.Set(0x00ff);
397 0 : }
398 :
399 : bool
400 0 : BitFields::IsR5G5B5() const
401 : {
402 0 : return mRed.mBitWidth == 5 &&
403 0 : mGreen.mBitWidth == 5 &&
404 0 : mBlue.mBitWidth == 5 &&
405 0 : mAlpha.mMask == 0x0;
406 : }
407 :
408 : bool
409 0 : BitFields::IsR8G8B8() const
410 : {
411 0 : return mRed.mBitWidth == 8 &&
412 0 : mGreen.mBitWidth == 8 &&
413 0 : mBlue.mBitWidth == 8 &&
414 0 : mAlpha.mMask == 0x0;
415 : }
416 :
417 : uint32_t*
418 0 : nsBMPDecoder::RowBuffer()
419 : {
420 0 : if (mDownscaler) {
421 0 : return reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer()) + mCurrentPos;
422 : }
423 :
424 : // Convert from row (1..mHeight) to absolute line (0..mHeight-1).
425 0 : int32_t line = (mH.mHeight < 0)
426 0 : ? -mH.mHeight - mCurrentRow
427 0 : : mCurrentRow - 1;
428 0 : int32_t offset = line * mH.mWidth + mCurrentPos;
429 0 : return reinterpret_cast<uint32_t*>(mImageData) + offset;
430 : }
431 :
432 : void
433 0 : nsBMPDecoder::FinishRow()
434 : {
435 0 : if (mDownscaler) {
436 0 : mDownscaler->CommitRow();
437 :
438 0 : if (mDownscaler->HasInvalidation()) {
439 0 : DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
440 0 : PostInvalidation(invalidRect.mOriginalSizeRect,
441 0 : Some(invalidRect.mTargetSizeRect));
442 : }
443 : } else {
444 0 : PostInvalidation(IntRect(0, mCurrentRow, mH.mWidth, 1));
445 : }
446 0 : mCurrentRow--;
447 0 : }
448 :
449 : LexerResult
450 0 : nsBMPDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
451 : {
452 0 : MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
453 :
454 : return mLexer.Lex(aIterator, aOnResume,
455 0 : [=](State aState, const char* aData, size_t aLength) {
456 0 : switch (aState) {
457 0 : case State::FILE_HEADER: return ReadFileHeader(aData, aLength);
458 0 : case State::INFO_HEADER_SIZE: return ReadInfoHeaderSize(aData, aLength);
459 0 : case State::INFO_HEADER_REST: return ReadInfoHeaderRest(aData, aLength);
460 0 : case State::BITFIELDS: return ReadBitfields(aData, aLength);
461 0 : case State::COLOR_TABLE: return ReadColorTable(aData, aLength);
462 0 : case State::GAP: return SkipGap();
463 0 : case State::AFTER_GAP: return AfterGap();
464 0 : case State::PIXEL_ROW: return ReadPixelRow(aData);
465 0 : case State::RLE_SEGMENT: return ReadRLESegment(aData);
466 0 : case State::RLE_DELTA: return ReadRLEDelta(aData);
467 0 : case State::RLE_ABSOLUTE: return ReadRLEAbsolute(aData, aLength);
468 : default:
469 0 : MOZ_CRASH("Unknown State");
470 : }
471 0 : });
472 : }
473 :
474 : LexerTransition<nsBMPDecoder::State>
475 0 : nsBMPDecoder::ReadFileHeader(const char* aData, size_t aLength)
476 : {
477 0 : mPreGapLength += aLength;
478 :
479 0 : bool signatureOk = aData[0] == 'B' && aData[1] == 'M';
480 0 : if (!signatureOk) {
481 0 : return Transition::TerminateFailure();
482 : }
483 :
484 : // We ignore the filesize (aData + 2) and reserved (aData + 6) fields.
485 :
486 0 : mH.mDataOffset = LittleEndian::readUint32(aData + 10);
487 :
488 0 : return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
489 : }
490 :
491 : // We read the info header in two steps: (a) read the mBIHSize field to
492 : // determine how long the header is; (b) read the rest of the header.
493 : LexerTransition<nsBMPDecoder::State>
494 0 : nsBMPDecoder::ReadInfoHeaderSize(const char* aData, size_t aLength)
495 : {
496 0 : mPreGapLength += aLength;
497 :
498 0 : mH.mBIHSize = LittleEndian::readUint32(aData);
499 :
500 0 : bool bihSizeOk = mH.mBIHSize == InfoHeaderLength::WIN_V2 ||
501 0 : mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
502 0 : mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
503 0 : mH.mBIHSize == InfoHeaderLength::WIN_V5 ||
504 0 : (mH.mBIHSize >= InfoHeaderLength::OS2_V2_MIN &&
505 0 : mH.mBIHSize <= InfoHeaderLength::OS2_V2_MAX);
506 0 : if (!bihSizeOk) {
507 0 : 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 0 : MOZ_ASSERT_IF(mIsWithinICO, mH.mBIHSize == InfoHeaderLength::WIN_V3);
512 :
513 : return Transition::To(State::INFO_HEADER_REST,
514 0 : mH.mBIHSize - BIHSIZE_FIELD_LENGTH);
515 : }
516 :
517 : LexerTransition<nsBMPDecoder::State>
518 0 : nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
519 : {
520 0 : mPreGapLength += aLength;
521 :
522 : // |mWidth| and |mHeight| may be signed (Windows) or unsigned (OS/2). We just
523 : // read as unsigned because in practice that's good enough.
524 0 : if (mH.mBIHSize == InfoHeaderLength::WIN_V2) {
525 0 : mH.mWidth = LittleEndian::readUint16(aData + 0);
526 0 : mH.mHeight = LittleEndian::readUint16(aData + 2);
527 : // We ignore the planes (aData + 4) field; it should always be 1.
528 0 : mH.mBpp = LittleEndian::readUint16(aData + 6);
529 : } else {
530 0 : mH.mWidth = LittleEndian::readUint32(aData + 0);
531 0 : mH.mHeight = LittleEndian::readUint32(aData + 4);
532 : // We ignore the planes (aData + 4) field; it should always be 1.
533 0 : mH.mBpp = LittleEndian::readUint16(aData + 10);
534 :
535 : // For OS2-BMPv2 the info header may be as little as 16 bytes, so be
536 : // careful for these fields.
537 0 : mH.mCompression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0;
538 0 : mH.mImageSize = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0;
539 : // We ignore the xppm (aData + 20) and yppm (aData + 24) fields.
540 0 : mH.mNumColors = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0;
541 : // We ignore the important_colors (aData + 36) field.
542 :
543 : // For WinBMPv4, WinBMPv5 and (possibly) OS2-BMPv2 there are additional
544 : // fields in the info header which we ignore, with the possible exception
545 : // of the color bitfields (see below).
546 : }
547 :
548 : // Run with MOZ_LOG=BMPDecoder:5 set to see this output.
549 0 : MOZ_LOG(sBMPLog, LogLevel::Debug,
550 : ("BMP: bihsize=%u, %d x %d, bpp=%u, compression=%u, colors=%u\n",
551 : mH.mBIHSize, mH.mWidth, mH.mHeight, uint32_t(mH.mBpp),
552 : mH.mCompression, mH.mNumColors));
553 :
554 : // BMPs with negative width are invalid. Also, reject extremely wide images
555 : // to keep the math sane. And reject INT_MIN as a height because you can't
556 : // get its absolute value (because -INT_MIN is one more than INT_MAX).
557 0 : const int32_t k64KWidth = 0x0000FFFF;
558 0 : bool sizeOk = 0 <= mH.mWidth && mH.mWidth <= k64KWidth &&
559 0 : mH.mHeight != INT_MIN;
560 0 : if (!sizeOk) {
561 0 : return Transition::TerminateFailure();
562 : }
563 :
564 : // Check mBpp and mCompression.
565 : bool bppCompressionOk =
566 0 : (mH.mCompression == Compression::RGB &&
567 0 : (mH.mBpp == 1 || mH.mBpp == 4 || mH.mBpp == 8 ||
568 0 : mH.mBpp == 16 || mH.mBpp == 24 || mH.mBpp == 32)) ||
569 0 : (mH.mCompression == Compression::RLE8 && mH.mBpp == 8) ||
570 0 : (mH.mCompression == Compression::RLE4 && mH.mBpp == 4) ||
571 0 : (mH.mCompression == Compression::BITFIELDS &&
572 : // For BITFIELDS compression we require an exact match for one of the
573 : // WinBMP BIH sizes; this clearly isn't an OS2 BMP.
574 0 : (mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
575 0 : mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
576 0 : mH.mBIHSize == InfoHeaderLength::WIN_V5) &&
577 0 : (mH.mBpp == 16 || mH.mBpp == 32));
578 0 : if (!bppCompressionOk) {
579 0 : return Transition::TerminateFailure();
580 : }
581 :
582 : // Initialize our current row to the top of the image.
583 0 : mCurrentRow = AbsoluteHeight();
584 :
585 : // Round it up to the nearest byte count, then pad to 4-byte boundary.
586 : // Compute this even for a metadate decode because GetCompressedImageSize()
587 : // relies on it.
588 0 : mPixelRowSize = (mH.mBpp * mH.mWidth + 7) / 8;
589 0 : uint32_t surplus = mPixelRowSize % 4;
590 0 : if (surplus != 0) {
591 0 : mPixelRowSize += 4 - surplus;
592 : }
593 :
594 0 : size_t bitFieldsLengthStillToRead = 0;
595 0 : if (mH.mCompression == Compression::BITFIELDS) {
596 : // Need to read bitfields.
597 0 : if (mH.mBIHSize >= InfoHeaderLength::WIN_V4) {
598 : // Bitfields are present in the info header, so we can read them
599 : // immediately.
600 0 : mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true);
601 : } else {
602 : // Bitfields are present after the info header, so we will read them in
603 : // ReadBitfields().
604 0 : bitFieldsLengthStillToRead = BitFields::LENGTH;
605 : }
606 0 : } else if (mH.mBpp == 16) {
607 : // No bitfields specified; use the default 5-5-5 values.
608 0 : mBitFields.SetR5G5B5();
609 0 : } else if (mH.mBpp == 32) {
610 : // No bitfields specified; use the default 8-8-8 values.
611 0 : mBitFields.SetR8G8B8();
612 : }
613 :
614 0 : return Transition::To(State::BITFIELDS, bitFieldsLengthStillToRead);
615 : }
616 :
617 : void
618 0 : BitFields::ReadFromHeader(const char* aData, bool aReadAlpha)
619 : {
620 0 : mRed.Set (LittleEndian::readUint32(aData + 0));
621 0 : mGreen.Set(LittleEndian::readUint32(aData + 4));
622 0 : mBlue.Set (LittleEndian::readUint32(aData + 8));
623 0 : if (aReadAlpha) {
624 0 : mAlpha.Set(LittleEndian::readUint32(aData + 12));
625 : }
626 0 : }
627 :
628 : LexerTransition<nsBMPDecoder::State>
629 0 : nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength)
630 : {
631 0 : mPreGapLength += aLength;
632 :
633 : // If aLength is zero there are no bitfields to read, or we already read them
634 : // in ReadInfoHeader().
635 0 : if (aLength != 0) {
636 0 : mBitFields.ReadFromHeader(aData, /* aReadAlpha = */ false);
637 : }
638 :
639 : // Note that RLE-encoded BMPs might be transparent because the 'delta' mode
640 : // can skip pixels and cause implicit transparency.
641 0 : mMayHaveTransparency =
642 0 : mIsWithinICO ||
643 0 : mH.mCompression == Compression::RLE8 ||
644 0 : mH.mCompression == Compression::RLE4 ||
645 0 : (mH.mCompression == Compression::BITFIELDS &&
646 0 : mBitFields.mAlpha.IsPresent());
647 0 : if (mMayHaveTransparency) {
648 0 : PostHasTransparency();
649 : }
650 :
651 : // Post our size to the superclass.
652 0 : PostSize(mH.mWidth, AbsoluteHeight());
653 :
654 : // We've now read all the headers. If we're doing a metadata decode, we're
655 : // done.
656 0 : if (IsMetadataDecode()) {
657 0 : return Transition::TerminateSuccess();
658 : }
659 :
660 : // Set up the color table, if present; it'll be filled in by ReadColorTable().
661 0 : if (mH.mBpp <= 8) {
662 0 : mNumColors = 1 << mH.mBpp;
663 0 : if (0 < mH.mNumColors && mH.mNumColors < mNumColors) {
664 0 : mNumColors = mH.mNumColors;
665 : }
666 :
667 : // Always allocate and zero 256 entries, even though mNumColors might be
668 : // smaller, because the file might erroneously index past mNumColors.
669 0 : mColors = MakeUnique<ColorTableEntry[]>(256);
670 0 : memset(mColors.get(), 0, 256 * sizeof(ColorTableEntry));
671 :
672 : // OS/2 Bitmaps have no padding byte.
673 0 : mBytesPerColor = (mH.mBIHSize == InfoHeaderLength::WIN_V2) ? 3 : 4;
674 : }
675 :
676 0 : MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
677 0 : nsresult rv = AllocateFrame(/* aFrameNum = */ 0, OutputSize(),
678 0 : FullOutputFrame(),
679 0 : mMayHaveTransparency ? SurfaceFormat::B8G8R8A8
680 0 : : SurfaceFormat::B8G8R8X8);
681 0 : if (NS_FAILED(rv)) {
682 0 : return Transition::TerminateFailure();
683 : }
684 0 : MOZ_ASSERT(mImageData, "Should have a buffer now");
685 :
686 0 : if (mDownscaler) {
687 : // BMPs store their rows in reverse order, so the downscaler needs to
688 : // reverse them again when writing its output. Unless the height is
689 : // negative!
690 0 : rv = mDownscaler->BeginFrame(Size(), Nothing(),
691 0 : mImageData, mMayHaveTransparency,
692 0 : /* aFlipVertically = */ mH.mHeight >= 0);
693 0 : if (NS_FAILED(rv)) {
694 0 : return Transition::TerminateFailure();
695 : }
696 : }
697 :
698 0 : return Transition::To(State::COLOR_TABLE, mNumColors * mBytesPerColor);
699 : }
700 :
701 : LexerTransition<nsBMPDecoder::State>
702 0 : nsBMPDecoder::ReadColorTable(const char* aData, size_t aLength)
703 : {
704 0 : MOZ_ASSERT_IF(aLength != 0, mNumColors > 0 && mColors);
705 :
706 0 : mPreGapLength += aLength;
707 :
708 0 : for (uint32_t i = 0; i < mNumColors; i++) {
709 : // The format is BGR or BGR0.
710 0 : mColors[i].mBlue = uint8_t(aData[0]);
711 0 : mColors[i].mGreen = uint8_t(aData[1]);
712 0 : mColors[i].mRed = uint8_t(aData[2]);
713 0 : aData += mBytesPerColor;
714 : }
715 :
716 : // We know how many bytes we've read so far (mPreGapLength) and we know the
717 : // offset of the pixel data (mH.mDataOffset), so we can determine the length
718 : // of the gap (possibly zero) between the color table and the pixel data.
719 : //
720 : // If the gap is negative the file must be malformed (e.g. mH.mDataOffset
721 : // points into the middle of the color palette instead of past the end) and
722 : // we give up.
723 0 : if (mPreGapLength > mH.mDataOffset) {
724 0 : return Transition::TerminateFailure();
725 : }
726 :
727 0 : uint32_t gapLength = mH.mDataOffset - mPreGapLength;
728 0 : return Transition::ToUnbuffered(State::AFTER_GAP, State::GAP, gapLength);
729 : }
730 :
731 : LexerTransition<nsBMPDecoder::State>
732 0 : nsBMPDecoder::SkipGap()
733 : {
734 0 : return Transition::ContinueUnbuffered(State::GAP);
735 : }
736 :
737 : LexerTransition<nsBMPDecoder::State>
738 0 : nsBMPDecoder::AfterGap()
739 : {
740 : // If there are no pixels we can stop.
741 : //
742 : // XXX: normally, if there are no pixels we will have stopped decoding before
743 : // now, outside of this decoder. However, if the BMP is within an ICO file,
744 : // it's possible that the ICO claimed the image had a non-zero size while the
745 : // BMP claims otherwise. This test is to catch that awkward case. If we ever
746 : // come up with a more general solution to this ICO-and-BMP-disagree-on-size
747 : // problem, this test can be removed.
748 0 : if (mH.mWidth == 0 || mH.mHeight == 0) {
749 0 : return Transition::TerminateSuccess();
750 : }
751 :
752 0 : bool hasRLE = mH.mCompression == Compression::RLE8 ||
753 0 : mH.mCompression == Compression::RLE4;
754 : return hasRLE
755 : ? Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH)
756 0 : : Transition::To(State::PIXEL_ROW, mPixelRowSize);
757 : }
758 :
759 : LexerTransition<nsBMPDecoder::State>
760 0 : nsBMPDecoder::ReadPixelRow(const char* aData)
761 : {
762 0 : MOZ_ASSERT(mCurrentRow > 0);
763 0 : MOZ_ASSERT(mCurrentPos == 0);
764 :
765 0 : const uint8_t* src = reinterpret_cast<const uint8_t*>(aData);
766 0 : uint32_t* dst = RowBuffer();
767 0 : uint32_t lpos = mH.mWidth;
768 0 : switch (mH.mBpp) {
769 : case 1:
770 0 : while (lpos > 0) {
771 : int8_t bit;
772 : uint8_t idx;
773 0 : for (bit = 7; bit >= 0 && lpos > 0; bit--) {
774 0 : idx = (*src >> bit) & 1;
775 0 : SetPixel(dst, idx, mColors);
776 0 : --lpos;
777 : }
778 0 : ++src;
779 : }
780 0 : break;
781 :
782 : case 4:
783 0 : while (lpos > 0) {
784 0 : Set4BitPixel(dst, *src, lpos, mColors);
785 0 : ++src;
786 : }
787 0 : break;
788 :
789 : case 8:
790 0 : while (lpos > 0) {
791 0 : SetPixel(dst, *src, mColors);
792 0 : --lpos;
793 0 : ++src;
794 : }
795 0 : break;
796 :
797 : case 16:
798 0 : if (mBitFields.IsR5G5B5()) {
799 : // Specialize this common case.
800 0 : while (lpos > 0) {
801 0 : uint16_t val = LittleEndian::readUint16(src);
802 0 : SetPixel(dst, mBitFields.mRed.Get5(val),
803 0 : mBitFields.mGreen.Get5(val),
804 0 : mBitFields.mBlue.Get5(val));
805 0 : --lpos;
806 0 : src += 2;
807 : }
808 : } else {
809 0 : bool anyHasAlpha = false;
810 0 : while (lpos > 0) {
811 0 : uint16_t val = LittleEndian::readUint16(src);
812 0 : SetPixel(dst, mBitFields.mRed.Get(val),
813 0 : mBitFields.mGreen.Get(val),
814 0 : mBitFields.mBlue.Get(val),
815 0 : mBitFields.mAlpha.GetAlpha(val, anyHasAlpha));
816 0 : --lpos;
817 0 : src += 2;
818 : }
819 0 : if (anyHasAlpha) {
820 0 : MOZ_ASSERT(mMayHaveTransparency);
821 0 : mDoesHaveTransparency = true;
822 : }
823 : }
824 0 : break;
825 :
826 : case 24:
827 0 : while (lpos > 0) {
828 0 : SetPixel(dst, src[2], src[1], src[0]);
829 0 : --lpos;
830 0 : src += 3;
831 : }
832 0 : break;
833 :
834 : case 32:
835 0 : if (mH.mCompression == Compression::RGB && mIsWithinICO &&
836 0 : mH.mBpp == 32) {
837 : // This is a special case only used for 32bpp WinBMPv3-ICO files, which
838 : // could be in either 0RGB or ARGB format. We start by assuming it's
839 : // an 0RGB image. If we hit a non-zero alpha value, then we know it's
840 : // actually an ARGB image, and change tack accordingly.
841 : // (Note: a fully-transparent ARGB image is indistinguishable from a
842 : // 0RGB image, and we will render such an image as a 0RGB image, i.e.
843 : // opaquely. This is unlikely to be a problem in practice.)
844 0 : while (lpos > 0) {
845 0 : if (!mDoesHaveTransparency && src[3] != 0) {
846 : // Up until now this looked like an 0RGB image, but we now know
847 : // it's actually an ARGB image. Which means every pixel we've seen
848 : // so far has been fully transparent. So we go back and redo them.
849 :
850 : // Tell the Downscaler to go back to the start.
851 0 : if (mDownscaler) {
852 0 : mDownscaler->ResetForNextProgressivePass();
853 : }
854 :
855 : // Redo the complete rows we've already done.
856 0 : MOZ_ASSERT(mCurrentPos == 0);
857 0 : int32_t currentRow = mCurrentRow;
858 0 : mCurrentRow = AbsoluteHeight();
859 0 : while (mCurrentRow > currentRow) {
860 0 : dst = RowBuffer();
861 0 : for (int32_t i = 0; i < mH.mWidth; i++) {
862 0 : SetPixel(dst, 0, 0, 0, 0);
863 : }
864 0 : FinishRow();
865 : }
866 :
867 : // Redo the part of this row we've already done.
868 0 : dst = RowBuffer();
869 0 : int32_t n = mH.mWidth - lpos;
870 0 : for (int32_t i = 0; i < n; i++) {
871 0 : SetPixel(dst, 0, 0, 0, 0);
872 : }
873 :
874 0 : MOZ_ASSERT(mMayHaveTransparency);
875 0 : mDoesHaveTransparency = true;
876 : }
877 :
878 : // If mDoesHaveTransparency is false, treat this as an 0RGB image.
879 : // Otherwise, treat this as an ARGB image.
880 0 : SetPixel(dst, src[2], src[1], src[0],
881 0 : mDoesHaveTransparency ? src[3] : 0xff);
882 0 : src += 4;
883 0 : --lpos;
884 0 : }
885 0 : } else if (mBitFields.IsR8G8B8()) {
886 : // Specialize this common case.
887 0 : while (lpos > 0) {
888 0 : uint32_t val = LittleEndian::readUint32(src);
889 0 : SetPixel(dst, mBitFields.mRed.Get8(val),
890 0 : mBitFields.mGreen.Get8(val),
891 0 : mBitFields.mBlue.Get8(val));
892 0 : --lpos;
893 0 : src += 4;
894 : }
895 : } else {
896 0 : bool anyHasAlpha = false;
897 0 : while (lpos > 0) {
898 0 : uint32_t val = LittleEndian::readUint32(src);
899 0 : SetPixel(dst, mBitFields.mRed.Get(val),
900 0 : mBitFields.mGreen.Get(val),
901 0 : mBitFields.mBlue.Get(val),
902 0 : mBitFields.mAlpha.GetAlpha(val, anyHasAlpha));
903 0 : --lpos;
904 0 : src += 4;
905 : }
906 0 : if (anyHasAlpha) {
907 0 : MOZ_ASSERT(mMayHaveTransparency);
908 0 : mDoesHaveTransparency = true;
909 : }
910 : }
911 0 : break;
912 :
913 : default:
914 0 : MOZ_CRASH("Unsupported color depth; earlier check didn't catch it?");
915 : }
916 :
917 0 : FinishRow();
918 0 : return mCurrentRow == 0
919 : ? Transition::TerminateSuccess()
920 0 : : Transition::To(State::PIXEL_ROW, mPixelRowSize);
921 : }
922 :
923 : LexerTransition<nsBMPDecoder::State>
924 0 : nsBMPDecoder::ReadRLESegment(const char* aData)
925 : {
926 0 : if (mCurrentRow == 0) {
927 0 : return Transition::TerminateSuccess();
928 : }
929 :
930 0 : uint8_t byte1 = uint8_t(aData[0]);
931 0 : uint8_t byte2 = uint8_t(aData[1]);
932 :
933 0 : if (byte1 != RLE::ESCAPE) {
934 : // Encoded mode consists of two bytes: byte1 specifies the number of
935 : // consecutive pixels to be drawn using the color index contained in
936 : // byte2.
937 : //
938 : // Work around bitmaps that specify too many pixels.
939 : uint32_t pixelsNeeded =
940 0 : std::min<uint32_t>(mH.mWidth - mCurrentPos, byte1);
941 0 : if (pixelsNeeded) {
942 0 : uint32_t* dst = RowBuffer();
943 0 : mCurrentPos += pixelsNeeded;
944 0 : if (mH.mCompression == Compression::RLE8) {
945 0 : do {
946 0 : SetPixel(dst, byte2, mColors);
947 0 : pixelsNeeded --;
948 0 : } while (pixelsNeeded);
949 : } else {
950 0 : do {
951 0 : Set4BitPixel(dst, byte2, pixelsNeeded, mColors);
952 0 : } while (pixelsNeeded);
953 : }
954 : }
955 0 : return Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH);
956 : }
957 :
958 0 : if (byte2 == RLE::ESCAPE_EOL) {
959 0 : mCurrentPos = 0;
960 0 : FinishRow();
961 0 : return mCurrentRow == 0
962 : ? Transition::TerminateSuccess()
963 0 : : Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH);
964 : }
965 :
966 0 : if (byte2 == RLE::ESCAPE_EOF) {
967 0 : return Transition::TerminateSuccess();
968 : }
969 :
970 0 : if (byte2 == RLE::ESCAPE_DELTA) {
971 0 : return Transition::To(State::RLE_DELTA, RLE::DELTA_LENGTH);
972 : }
973 :
974 : // Absolute mode. |byte2| gives the number of pixels. The length depends on
975 : // whether it's 4-bit or 8-bit RLE. Also, the length must be even (and zero
976 : // padding is used to achieve this when necessary).
977 0 : MOZ_ASSERT(mAbsoluteModeNumPixels == 0);
978 0 : mAbsoluteModeNumPixels = byte2;
979 0 : uint32_t length = byte2;
980 0 : if (mH.mCompression == Compression::RLE4) {
981 0 : length = (length + 1) / 2; // halve, rounding up
982 : }
983 0 : if (length & 1) {
984 0 : length++;
985 : }
986 0 : return Transition::To(State::RLE_ABSOLUTE, length);
987 : }
988 :
989 : LexerTransition<nsBMPDecoder::State>
990 0 : nsBMPDecoder::ReadRLEDelta(const char* aData)
991 : {
992 : // Delta encoding makes it possible to skip pixels making part of the image
993 : // transparent.
994 0 : MOZ_ASSERT(mMayHaveTransparency);
995 0 : mDoesHaveTransparency = true;
996 :
997 0 : if (mDownscaler) {
998 : // Clear the skipped pixels. (This clears to the end of the row,
999 : // which is perfect if there's a Y delta and harmless if not).
1000 0 : mDownscaler->ClearRestOfRow(/* aStartingAtCol = */ mCurrentPos);
1001 : }
1002 :
1003 : // Handle the XDelta.
1004 0 : mCurrentPos += uint8_t(aData[0]);
1005 0 : if (mCurrentPos > mH.mWidth) {
1006 0 : mCurrentPos = mH.mWidth;
1007 : }
1008 :
1009 : // Handle the Y Delta.
1010 0 : int32_t yDelta = std::min<int32_t>(uint8_t(aData[1]), mCurrentRow);
1011 0 : mCurrentRow -= yDelta;
1012 :
1013 0 : if (mDownscaler && yDelta > 0) {
1014 : // Commit the current row (the first of the skipped rows).
1015 0 : mDownscaler->CommitRow();
1016 :
1017 : // Clear and commit the remaining skipped rows.
1018 0 : for (int32_t line = 1; line < yDelta; line++) {
1019 0 : mDownscaler->ClearRow();
1020 0 : mDownscaler->CommitRow();
1021 : }
1022 : }
1023 :
1024 0 : return mCurrentRow == 0
1025 : ? Transition::TerminateSuccess()
1026 0 : : Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH);
1027 : }
1028 :
1029 : LexerTransition<nsBMPDecoder::State>
1030 0 : nsBMPDecoder::ReadRLEAbsolute(const char* aData, size_t aLength)
1031 : {
1032 0 : uint32_t n = mAbsoluteModeNumPixels;
1033 0 : mAbsoluteModeNumPixels = 0;
1034 :
1035 0 : if (mCurrentPos + n > uint32_t(mH.mWidth)) {
1036 : // Bad data. Stop decoding; at least part of the image may have been
1037 : // decoded.
1038 0 : return Transition::TerminateSuccess();
1039 : }
1040 :
1041 : // In absolute mode, n represents the number of pixels that follow, each of
1042 : // which contains the color index of a single pixel.
1043 0 : uint32_t* dst = RowBuffer();
1044 0 : uint32_t iSrc = 0;
1045 0 : uint32_t* oldPos = dst;
1046 0 : if (mH.mCompression == Compression::RLE8) {
1047 0 : while (n > 0) {
1048 0 : SetPixel(dst, aData[iSrc], mColors);
1049 0 : n--;
1050 0 : iSrc++;
1051 : }
1052 : } else {
1053 0 : while (n > 0) {
1054 0 : Set4BitPixel(dst, aData[iSrc], n, mColors);
1055 0 : iSrc++;
1056 : }
1057 : }
1058 0 : mCurrentPos += dst - oldPos;
1059 :
1060 : // We should read all the data (unless the last byte is zero padding).
1061 0 : MOZ_ASSERT(iSrc == aLength - 1 || iSrc == aLength);
1062 :
1063 0 : return Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH);
1064 : }
1065 :
1066 : } // namespace image
1067 : } // namespace mozilla
|