OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. | 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 1
59, | 59 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 1
59, |
60 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 1
91, | 60 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 1
91, |
61 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 2
23, | 61 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 2
23, |
62 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 2
55, | 62 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 2
55, |
63 }; | 63 }; |
64 | 64 |
65 } | 65 } |
66 | 66 |
67 namespace WebCore { | 67 namespace WebCore { |
68 | 68 |
69 BMPImageReader::BMPImageReader(ImageDecoder* parent, size_t decodedAndHeaderOffs
et, size_t imgDataOffset, bool usesAndMask) | 69 BMPImageReader::BMPImageReader(ImageDecoder* parent, size_t decodedAndHeaderOffs
et, size_t imgDataOffset, bool isInICO) |
70 : m_parent(parent) | 70 : m_parent(parent) |
71 , m_buffer(0) | 71 , m_buffer(0) |
72 , m_decodedOffset(decodedAndHeaderOffset) | 72 , m_decodedOffset(decodedAndHeaderOffset) |
73 , m_headerOffset(decodedAndHeaderOffset) | 73 , m_headerOffset(decodedAndHeaderOffset) |
74 , m_imgDataOffset(imgDataOffset) | 74 , m_imgDataOffset(imgDataOffset) |
75 , m_isOS21x(false) | 75 , m_isOS21x(false) |
76 , m_isOS22x(false) | 76 , m_isOS22x(false) |
77 , m_isTopDown(false) | 77 , m_isTopDown(false) |
78 , m_needToProcessBitmasks(false) | 78 , m_needToProcessBitmasks(false) |
79 , m_needToProcessColorTable(false) | 79 , m_needToProcessColorTable(false) |
80 , m_seenNonZeroAlphaPixel(false) | 80 , m_seenNonZeroAlphaPixel(false) |
81 , m_seenZeroAlphaPixel(false) | 81 , m_seenZeroAlphaPixel(false) |
82 , m_andMaskState(usesAndMask ? NotYetDecoded : None) | 82 , m_isInICO(isInICO) |
| 83 , m_decodingAndMask(false) |
83 { | 84 { |
84 // Clue-in decodeBMP() that we need to detect the correct info header size. | 85 // Clue-in decodeBMP() that we need to detect the correct info header size. |
85 memset(&m_infoHeader, 0, sizeof(m_infoHeader)); | 86 memset(&m_infoHeader, 0, sizeof(m_infoHeader)); |
86 } | 87 } |
87 | 88 |
88 bool BMPImageReader::decodeBMP(bool onlySize) | 89 bool BMPImageReader::decodeBMP(bool onlySize) |
89 { | 90 { |
90 // Calculate size of info header. | 91 // Calculate size of info header. |
91 if (!m_infoHeader.biSize && !readInfoHeaderSize()) | 92 if (!m_infoHeader.biSize && !readInfoHeaderSize()) |
92 return false; | 93 return false; |
(...skipping 26 matching lines...) Expand all Loading... |
119 m_buffer->setHasAlpha(false); | 120 m_buffer->setHasAlpha(false); |
120 | 121 |
121 // For BMPs, the frame always fills the entire image. | 122 // For BMPs, the frame always fills the entire image. |
122 m_buffer->setOriginalFrameRect(IntRect(IntPoint(), m_parent->size())); | 123 m_buffer->setOriginalFrameRect(IntRect(IntPoint(), m_parent->size())); |
123 | 124 |
124 if (!m_isTopDown) | 125 if (!m_isTopDown) |
125 m_coord.setY(m_parent->size().height() - 1); | 126 m_coord.setY(m_parent->size().height() - 1); |
126 } | 127 } |
127 | 128 |
128 // Decode the data. | 129 // Decode the data. |
129 if ((m_andMaskState != Decoding) && !pastEndOfImage(0)) { | 130 if (!m_decodingAndMask && !pastEndOfImage(0)) { |
130 if ((m_infoHeader.biCompression != RLE4) && (m_infoHeader.biCompression
!= RLE8) && (m_infoHeader.biCompression != RLE24)) { | 131 if ((m_infoHeader.biCompression != RLE4) && (m_infoHeader.biCompression
!= RLE8) && (m_infoHeader.biCompression != RLE24)) { |
131 const ProcessingResult result = processNonRLEData(false, 0); | 132 const ProcessingResult result = processNonRLEData(false, 0); |
132 if (result != Success) | 133 if (result != Success) |
133 return (result == Failure) ? m_parent->setFailed() : false; | 134 return (result == Failure) ? m_parent->setFailed() : false; |
134 } else if (!processRLEData()) | 135 } else if (!processRLEData()) |
135 return false; | 136 return false; |
136 } | 137 } |
137 | 138 |
138 // If the image has an AND mask and there was no alpha data, process the | 139 // If the image has an AND mask and there was no alpha data, process the |
139 // mask. | 140 // mask. |
140 if ((m_andMaskState == NotYetDecoded) && !m_buffer->hasAlpha()) { | 141 if (m_isInICO && !m_decodingAndMask && !m_buffer->hasAlpha()) { |
141 // Reset decoding coordinates to start of image. | 142 // Reset decoding coordinates to start of image. |
142 m_coord.setX(0); | 143 m_coord.setX(0); |
143 m_coord.setY(m_isTopDown ? 0 : (m_parent->size().height() - 1)); | 144 m_coord.setY(m_isTopDown ? 0 : (m_parent->size().height() - 1)); |
144 | 145 |
145 // The AND mask is stored as 1-bit data. | 146 // The AND mask is stored as 1-bit data. |
146 m_infoHeader.biBitCount = 1; | 147 m_infoHeader.biBitCount = 1; |
147 | 148 |
148 m_andMaskState = Decoding; | 149 m_decodingAndMask = true; |
149 } | 150 } |
150 if (m_andMaskState == Decoding) { | 151 if (m_decodingAndMask) { |
151 const ProcessingResult result = processNonRLEData(false, 0); | 152 const ProcessingResult result = processNonRLEData(false, 0); |
152 if (result != Success) | 153 if (result != Success) |
153 return (result == Failure) ? m_parent->setFailed() : false; | 154 return (result == Failure) ? m_parent->setFailed() : false; |
154 } | 155 } |
155 | 156 |
156 // Done! | 157 // Done! |
157 m_buffer->setStatus(ImageFrame::FrameComplete); | 158 m_buffer->setStatus(ImageFrame::FrameComplete); |
158 return true; | 159 return true; |
159 } | 160 } |
160 | 161 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 | 235 |
235 bool BMPImageReader::readInfoHeader() | 236 bool BMPImageReader::readInfoHeader() |
236 { | 237 { |
237 // Pre-initialize some fields that not all headers set. | 238 // Pre-initialize some fields that not all headers set. |
238 m_infoHeader.biCompression = RGB; | 239 m_infoHeader.biCompression = RGB; |
239 m_infoHeader.biClrUsed = 0; | 240 m_infoHeader.biClrUsed = 0; |
240 | 241 |
241 if (m_isOS21x) { | 242 if (m_isOS21x) { |
242 m_infoHeader.biWidth = readUint16(4); | 243 m_infoHeader.biWidth = readUint16(4); |
243 m_infoHeader.biHeight = readUint16(6); | 244 m_infoHeader.biHeight = readUint16(6); |
244 ASSERT(m_andMaskState == None); // ICO is a Windows format, not OS/2! | 245 ASSERT(!m_isInICO); // ICO is a Windows format, not OS/2! |
245 m_infoHeader.biBitCount = readUint16(10); | 246 m_infoHeader.biBitCount = readUint16(10); |
246 return true; | 247 return true; |
247 } | 248 } |
248 | 249 |
249 m_infoHeader.biWidth = readUint32(4); | 250 m_infoHeader.biWidth = readUint32(4); |
250 m_infoHeader.biHeight = readUint32(8); | 251 m_infoHeader.biHeight = readUint32(8); |
251 if (m_andMaskState != None) | 252 if (m_isInICO) |
252 m_infoHeader.biHeight /= 2; | 253 m_infoHeader.biHeight /= 2; |
253 m_infoHeader.biBitCount = readUint16(14); | 254 m_infoHeader.biBitCount = readUint16(14); |
254 | 255 |
255 // Read compression type, if present. | 256 // Read compression type, if present. |
256 if (m_infoHeader.biSize >= 20) { | 257 if (m_infoHeader.biSize >= 20) { |
257 uint32_t biCompression = readUint32(16); | 258 uint32_t biCompression = readUint32(16); |
258 | 259 |
259 // Detect OS/2 2.x-specific compression types. | 260 // Detect OS/2 2.x-specific compression types. |
260 if ((biCompression == 3) && (m_infoHeader.biBitCount == 1)) { | 261 if ((biCompression == 3) && (m_infoHeader.biBitCount == 1)) { |
261 m_infoHeader.biCompression = HUFFMAN1D; | 262 m_infoHeader.biCompression = HUFFMAN1D; |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 } | 434 } |
434 | 435 |
435 // Alpha is a poorly-documented and inconsistently-used feature. | 436 // Alpha is a poorly-documented and inconsistently-used feature. |
436 // | 437 // |
437 // Windows V4+ has an alpha bitmask in the info header. Unlike the R/G/B | 438 // Windows V4+ has an alpha bitmask in the info header. Unlike the R/G/B |
438 // bitmasks, the MSDN docs don't indicate that it is only valid for the | 439 // bitmasks, the MSDN docs don't indicate that it is only valid for the |
439 // BITFIELDS compression format, so we respect it at all times. | 440 // BITFIELDS compression format, so we respect it at all times. |
440 // | 441 // |
441 // To complicate things, Windows V3 BMPs, which lack this mask, can specify | 442 // To complicate things, Windows V3 BMPs, which lack this mask, can specify |
442 // 32bpp format, which to any sane reader would imply an 8-bit alpha | 443 // 32bpp format, which to any sane reader would imply an 8-bit alpha |
443 // channel -- and indeed, there exist BMPs in this format which clearly | 444 // channel -- and for BMPs-in-ICOs, that's precisely what's intended to |
| 445 // happen. There also exist standalone BMPs in this format which clearly |
444 // expect the alpha channel to be respected. However, there are many other | 446 // expect the alpha channel to be respected. However, there are many other |
445 // BMPs which, for example, fill this channel with all 0s, yet clearly | 447 // BMPs which, for example, fill this channel with all 0s, yet clearly |
446 // expect to not be displayed as a fully-transparent rectangle. | 448 // expect to not be displayed as a fully-transparent rectangle. |
447 // | 449 // |
448 // If these were the only two types of Windows V3, 32bpp BMPs in the wild, | 450 // If these were the only two types of Windows V3, 32bpp BMPs in the wild, |
449 // we could distinguish between them by scanning the alpha channel in the | 451 // we could distinguish between them by scanning the alpha channel in the |
450 // image, looking for nonzero values, and only enabling alpha if we found | 452 // image, looking for nonzero values, and only enabling alpha if we found |
451 // some. (It turns out we have to do this anyway, because, crazily, there | 453 // some. (It turns out we have to do this anyway, because, crazily, there |
452 // are also Windows V4+ BMPs with an explicit, non-zero alpha mask, which | 454 // are also Windows V4+ BMPs with an explicit, non-zero alpha mask, which |
453 // then zero-fill their alpha channels! See comments in | 455 // then zero-fill their alpha channels! See comments in |
454 // processNonRLEData().) | 456 // processNonRLEData().) |
455 // | 457 // |
456 // Unfortunately there are also V3 BMPs -- indeed, probably more than the | 458 // Unfortunately there are also V3 BMPs -- indeed, probably more than the |
457 // number of 32bpp, V3 BMPs which intentionally use alpha -- which specify | 459 // number of 32bpp, V3 BMPs which intentionally use alpha -- which specify |
458 // 32bpp format, use nonzero (and non-255) alpha values, and yet expect to | 460 // 32bpp format, use nonzero (and non-255) alpha values, and yet expect to |
459 // be rendered fully-opaque. And other browsers do so. | 461 // be rendered fully-opaque. And other browsers do so. |
460 // | 462 // |
461 // So it's impossible to display every BMP in the way its creators intended, | 463 // So it's impossible to display every BMP in the way its creators intended, |
462 // and we have to choose what to break. Given the paragraph above, we match | 464 // and we have to choose what to break. Given the paragraph above, we match |
463 // other browsers and ignore alpha in Windows V3 BMPs. | 465 // other browsers and ignore alpha in Windows V3 BMPs except inside ICO |
| 466 // files. |
464 if (!isWindowsV4Plus()) | 467 if (!isWindowsV4Plus()) |
465 m_bitMasks[3] = 0; | 468 m_bitMasks[3] = (m_isInICO && (m_infoHeader.biCompression != BITFIELDS)
&& (m_infoHeader.biBitCount == 32)) ? static_cast<uint32_t>(0xff000000) : 0; |
466 | 469 |
467 // We've now decoded all the non-image data we care about. Skip anything | 470 // We've now decoded all the non-image data we care about. Skip anything |
468 // else before the actual raster data. | 471 // else before the actual raster data. |
469 if (m_imgDataOffset) | 472 if (m_imgDataOffset) |
470 m_decodedOffset = m_imgDataOffset; | 473 m_decodedOffset = m_imgDataOffset; |
471 m_needToProcessBitmasks = false; | 474 m_needToProcessBitmasks = false; |
472 | 475 |
473 // Check masks and set shift and LUT address values. | 476 // Check masks and set shift and LUT address values. |
474 for (int i = 0; i < 4; ++i) { | 477 for (int i = 0; i < 4; ++i) { |
475 // Trim the mask to the allowed bit depth. Some Windows V4+ BMPs | 478 // Trim the mask to the allowed bit depth. Some Windows V4+ BMPs |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
719 | 722 |
720 if (m_infoHeader.biBitCount < 16) { | 723 if (m_infoHeader.biBitCount < 16) { |
721 // Paletted data. Pixels are stored little-endian within bytes. | 724 // Paletted data. Pixels are stored little-endian within bytes. |
722 // Decode pixels one byte at a time, left to right (so, starting at | 725 // Decode pixels one byte at a time, left to right (so, starting at |
723 // the most significant bits in the byte). | 726 // the most significant bits in the byte). |
724 const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1; | 727 const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1; |
725 for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) { | 728 for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) { |
726 uint8_t pixelData = m_data->data()[m_decodedOffset + byte]; | 729 uint8_t pixelData = m_data->data()[m_decodedOffset + byte]; |
727 for (size_t pixel = 0; (pixel < pixelsPerByte) && (m_coord.x() <
endX); ++pixel) { | 730 for (size_t pixel = 0; (pixel < pixelsPerByte) && (m_coord.x() <
endX); ++pixel) { |
728 const size_t colorIndex = (pixelData >> (8 - m_infoHeader.bi
BitCount)) & mask; | 731 const size_t colorIndex = (pixelData >> (8 - m_infoHeader.bi
BitCount)) & mask; |
729 if (m_andMaskState == Decoding) { | 732 if (m_decodingAndMask) { |
730 // There's no way to accurately represent an AND + XOR | 733 // There's no way to accurately represent an AND + XOR |
731 // operation as an RGBA image, so where the AND values | 734 // operation as an RGBA image, so where the AND values |
732 // are 1, we simply set the framebuffer pixels to fully | 735 // are 1, we simply set the framebuffer pixels to fully |
733 // transparent, on the assumption that most ICOs on the | 736 // transparent, on the assumption that most ICOs on the |
734 // web will not be doing a lot of inverting. | 737 // web will not be doing a lot of inverting. |
735 if (colorIndex) { | 738 if (colorIndex) { |
736 setRGBA(0, 0, 0, 0); | 739 setRGBA(0, 0, 0, 0); |
737 m_buffer->setHasAlpha(true); | 740 m_buffer->setHasAlpha(true); |
738 } else | 741 } else |
739 m_coord.move(1, 0); | 742 m_coord.move(1, 0); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
789 // Finished decoding whole image. | 792 // Finished decoding whole image. |
790 return Success; | 793 return Success; |
791 } | 794 } |
792 | 795 |
793 void BMPImageReader::moveBufferToNextRow() | 796 void BMPImageReader::moveBufferToNextRow() |
794 { | 797 { |
795 m_coord.move(-m_coord.x(), m_isTopDown ? 1 : -1); | 798 m_coord.move(-m_coord.x(), m_isTopDown ? 1 : -1); |
796 } | 799 } |
797 | 800 |
798 } // namespace WebCore | 801 } // namespace WebCore |
OLD | NEW |