Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: Source/platform/image-decoders/bmp/BMPImageReader.cpp

Issue 279433002: BMP-in-ICO should respect alpha in Windows V3 32bpp RGB bitmaps. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698