Changeset 44874 in webkit
- Timestamp:
- Jun 19, 2009 2:49:25 PM (15 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r44869 r44874 1 2009-06-19 Peter Kasting <pkasting@google.com> 2 3 Reviewed by Eric Seidel. 4 5 https://bugs.webkit.org/show_bug.cgi?id=26460 part three 6 Make BMPImageReader a standalone class that is used by ICOImageDecoder 7 and BMPImageDecoder to decode individual BMPs within a file. These 8 decoders now inherit directly from ImageDecoder. 9 10 This also makes these decoders decode on-demand in isSizeAvailable() and 11 frameBufferAtIndex(), like the other decoders, instead of when setData() 12 is called, like before. This should provide a speedup on pages 13 containing BMPs that aren't immediately onscreen. 14 15 * platform/image-decoders/bmp/BMPImageDecoder.cpp: 16 (WebCore::BMPImageDecoder::BMPImageDecoder): 17 (WebCore::BMPImageDecoder::setData): 18 (WebCore::BMPImageDecoder::isSizeAvailable): 19 (WebCore::BMPImageDecoder::frameBufferAtIndex): 20 (WebCore::BMPImageDecoder::decodeWithCheckForDataEnded): 21 (WebCore::BMPImageDecoder::decode): 22 (WebCore::BMPImageDecoder::processFileHeader): 23 * platform/image-decoders/bmp/BMPImageDecoder.h: 24 (WebCore::BMPImageDecoder::readUint32): 25 * platform/image-decoders/bmp/BMPImageReader.cpp: 26 (WebCore::BMPImageReader::BMPImageReader): 27 (WebCore::BMPImageReader::decodeBMP): 28 (WebCore::BMPImageReader::readInfoHeaderSize): 29 (WebCore::BMPImageReader::processInfoHeader): 30 (WebCore::BMPImageReader::readInfoHeader): 31 (WebCore::BMPImageReader::processBitmasks): 32 (WebCore::BMPImageReader::processColorTable): 33 (WebCore::BMPImageReader::processRLEData): 34 (WebCore::BMPImageReader::processNonRLEData): 35 (WebCore::BMPImageReader::setFailed): 36 * platform/image-decoders/bmp/BMPImageReader.h: 37 (WebCore::BMPImageReader::readUint16): 38 (WebCore::BMPImageReader::readUint32): 39 (WebCore::BMPImageReader::setBuffer): 40 (WebCore::BMPImageReader::setData): 41 (WebCore::BMPImageReader::): 42 (WebCore::BMPImageReader::pastEndOfImage): 43 (WebCore::BMPImageReader::readCurrentPixel): 44 (WebCore::BMPImageReader::setRGBA): 45 * platform/image-decoders/ico/ICOImageDecoder.cpp: 46 (WebCore::ICOImageDecoder::ICOImageDecoder): 47 (WebCore::ICOImageDecoder::setData): 48 (WebCore::ICOImageDecoder::isSizeAvailable): 49 (WebCore::ICOImageDecoder::size): 50 (WebCore::ICOImageDecoder::frameBufferAtIndex): 51 (WebCore::ICOImageDecoder::decodeWithCheckForDataEnded): 52 (WebCore::ICOImageDecoder::decode): 53 (WebCore::ICOImageDecoder::processDirectory): 54 (WebCore::ICOImageDecoder::processDirectoryEntries): 55 (WebCore::ICOImageDecoder::readDirectoryEntry): 56 (WebCore::ICOImageDecoder::processImageType): 57 * platform/image-decoders/ico/ICOImageDecoder.h: 58 (WebCore::ICOImageDecoder::readUint16): 59 (WebCore::ICOImageDecoder::readUint32): 60 1 61 2009-06-19 Adam Barth <abarth@webkit.org> 2 62 -
trunk/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp
r44833 r44874 32 32 #include "BMPImageDecoder.h" 33 33 34 #include "BMPImageReader.h" 35 34 36 namespace WebCore { 35 37 … … 40 42 41 43 BMPImageDecoder::BMPImageDecoder() 42 : BMPImageReader() 44 : ImageDecoder() 45 , m_allDataReceived(false) 46 , m_decodedOffset(0) 43 47 { 44 48 } 45 49 46 void BMPImageDecoder:: decodeImage(SharedBuffer* data)50 void BMPImageDecoder::setData(SharedBuffer* data, bool allDataReceived) 47 51 { 48 // Read and process file header. 49 if ((m_decodedOffset < sizeOfFileHeader) && !processFileHeader(data)) 52 if (failed()) 50 53 return; 51 54 52 // Decode BMP. 53 decodeBMP(data); 55 ImageDecoder::setData(data, allDataReceived); 56 m_allDataReceived = allDataReceived; 57 if (m_reader) 58 m_reader->setData(data); 54 59 } 55 60 56 bool BMPImageDecoder:: processFileHeader(SharedBuffer* data)61 bool BMPImageDecoder::isSizeAvailable() 57 62 { 63 if (!ImageDecoder::isSizeAvailable() && !failed()) 64 decodeWithCheckForDataEnded(true); 65 66 return ImageDecoder::isSizeAvailable(); 67 } 68 69 RGBA32Buffer* BMPImageDecoder::frameBufferAtIndex(size_t index) 70 { 71 if (index) 72 return 0; 73 74 if (m_frameBufferCache.isEmpty()) 75 m_frameBufferCache.resize(1); 76 77 RGBA32Buffer* buffer = &m_frameBufferCache.first(); 78 if (buffer->status() != RGBA32Buffer::FrameComplete && !failed()) 79 decodeWithCheckForDataEnded(false); 80 return buffer; 81 } 82 83 void BMPImageDecoder::decodeWithCheckForDataEnded(bool onlySize) 84 { 85 if (failed()) 86 return; 87 88 // If we couldn't decode the image but we've received all the data, decoding 89 // has failed. 90 if (!decode(onlySize) && m_allDataReceived) 91 setFailed(); 92 } 93 94 bool BMPImageDecoder::decode(bool onlySize) 95 { 96 size_t imgDataOffset = 0; 97 if ((m_decodedOffset < sizeOfFileHeader) 98 && !processFileHeader(&imgDataOffset)) 99 return false; 100 101 if (!m_reader) { 102 m_reader.set(new BMPImageReader(this, m_decodedOffset, imgDataOffset, 103 false)); 104 m_reader->setData(m_data.get()); 105 } 106 107 if (!m_frameBufferCache.isEmpty()) 108 m_reader->setBuffer(&m_frameBufferCache.first()); 109 110 return m_reader->decodeBMP(onlySize); 111 } 112 113 bool BMPImageDecoder::processFileHeader(size_t* imgDataOffset) 114 { 115 ASSERT(imgDataOffset); 116 58 117 // Read file header. 59 118 ASSERT(!m_decodedOffset); 60 if ( data->size() < sizeOfFileHeader)119 if (m_data->size() < sizeOfFileHeader) 61 120 return false; 62 121 const uint16_t fileType = 63 ( data->data()[0] << 8) | static_cast<uint8_t>(data->data()[1]);64 m_imgDataOffset = readUint32(data,10);65 m_decodedOffset = m_headerOffset =sizeOfFileHeader;122 (m_data->data()[0] << 8) | static_cast<uint8_t>(m_data->data()[1]); 123 *imgDataOffset = readUint32(10); 124 m_decodedOffset = sizeOfFileHeader; 66 125 67 126 // See if this is a bitmap filetype we understand. -
trunk/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h
r44833 r44874 33 33 34 34 #include "BMPImageReader.h" 35 #include <wtf/OwnPtr.h> 35 36 36 37 namespace WebCore { 37 38 38 39 // This class decodes the BMP image format. 39 class BMPImageDecoder : public BMPImageReader {40 class BMPImageDecoder : public ImageDecoder { 40 41 public: 41 42 BMPImageDecoder(); 42 43 44 // ImageDecoder 43 45 virtual String filenameExtension() const { return "bmp"; } 44 45 // BMPImageReader46 virtual void decodeImage(SharedBuffer*);46 virtual void setData(SharedBuffer*, bool allDataReceived); 47 virtual bool isSizeAvailable(); 48 virtual RGBA32Buffer* frameBufferAtIndex(size_t index); 47 49 48 50 private: 49 inline uint32_t readUint32( SharedBuffer* data,int offset) const51 inline uint32_t readUint32(int offset) const 50 52 { 51 return readUint32Helper(data, m_decodedOffset + offset); 53 return BMPImageReader::readUint32(m_data.get(), 54 m_decodedOffset + offset); 52 55 } 53 56 54 // Processes the file header at the beginning of the data. Returns true if 55 // the file header could be decoded. 56 bool processFileHeader(SharedBuffer*); 57 // Decodes the image. If |onlySize| is true, stops decoding after 58 // calculating the image size. If decoding fails but there is no more 59 // data coming, sets the "decode failure" flag. 60 void decodeWithCheckForDataEnded(bool onlySize); 61 62 // Decodes the image. If |onlySize| is true, stops decoding after 63 // calculating the image size. Returns whether decoding succeeded. 64 // NOTE: Used internally by decodeWithCheckForDataEnded(). Other people 65 // should not call this. 66 bool decode(bool onlySize); 67 68 // Processes the file header at the beginning of the data. Sets 69 // |*imgDataOffset| based on the header contents. Returns true if the 70 // file header could be decoded. 71 bool processFileHeader(size_t* imgDataOffset); 72 73 // True if we've seen all the data. 74 bool m_allDataReceived; 75 76 // An index into |m_data| representing how much we've already decoded. 77 // Note that this only tracks data _this_ class decodes; once the 78 // BMPImageReader takes over this will not be updated further. 79 size_t m_decodedOffset; 80 81 // The reader used to do most of the BMP decoding. 82 OwnPtr<BMPImageReader> m_reader; 57 83 }; 58 84 -
trunk/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp
r44833 r44874 34 34 namespace WebCore { 35 35 36 BMPImageReader::BMPImageReader() 37 : m_decodedOffset(0) 38 , m_headerOffset(0) 39 , m_imgDataOffset(0) 40 , m_andMaskState(None) 36 BMPImageReader::BMPImageReader(ImageDecoder* parent, 37 size_t decodedAndHeaderOffset, 38 size_t imgDataOffset, 39 bool usesAndMask) 40 : m_parent(parent) 41 , m_buffer(0) 42 , m_decodedOffset(decodedAndHeaderOffset) 43 , m_headerOffset(decodedAndHeaderOffset) 44 , m_imgDataOffset(imgDataOffset) 45 , m_andMaskState(usesAndMask ? NotYetDecoded : None) 41 46 , m_isOS21x(false) 42 47 , m_isOS22x(false) … … 48 53 , m_seenZeroAlphaPixel(false) 49 54 { 50 m_frameBufferCache.resize(1);51 52 55 // Clue-in decodeBMP() that we need to detect the correct info header size. 53 56 memset(&m_infoHeader, 0, sizeof(m_infoHeader)); 54 57 } 55 58 56 void BMPImageReader::setData(SharedBuffer* data, bool allDataReceived) 57 { 58 ImageDecoder::setData(data, allDataReceived); 59 60 // NOTE: This function intentionally uses frameBufferAtIndex() instead of 61 // checking m_frameBufferCache.first() directly, so that it will do the 62 // right thing for ICOImageDecoder, which needs to override this accessor 63 // to support ICOs which contain PNGs. 64 65 // Return quickly when we can't do any more work. 66 if (m_failed || data->isEmpty() 67 || (frameBufferAtIndex(0)->status() == RGBA32Buffer::FrameComplete)) 68 return; 69 70 // Decode as much as we can. This assumes |data| starts at the beginning 71 // of the image data, rather than containing just the latest chunk. 72 decodeImage(data); 73 if (m_failed) { 74 // Handle failure before getting the framebuffer below. 75 m_colorTable.clear(); 76 return; 77 } 78 79 // If we got all the data but couldn't finish decoding, fail. 80 const bool finished = 81 (frameBufferAtIndex(0)->status() == RGBA32Buffer::FrameComplete); 82 if (allDataReceived && !finished) 83 m_failed = true; 84 85 // Release the color table when we no longer need it. 86 if (finished || m_failed) 87 m_colorTable.clear(); 88 } 89 90 RGBA32Buffer* BMPImageReader::frameBufferAtIndex(size_t index) 91 { 92 return index ? 0 : &m_frameBufferCache.first(); 93 } 94 95 bool BMPImageReader::decodeBMP(SharedBuffer* data) 59 bool BMPImageReader::decodeBMP(bool onlySize) 96 60 { 97 61 // Calculate size of info header. 98 if (!m_infoHeader.biSize && ! getInfoHeaderSize(data))62 if (!m_infoHeader.biSize && !readInfoHeaderSize()) 99 63 return false; 100 64 101 65 // Read and process info header. 102 66 if ((m_decodedOffset < (m_headerOffset + m_infoHeader.biSize)) 103 && !processInfoHeader(data)) 104 return false; 67 && !processInfoHeader()) 68 return false; 69 70 // processInfoHeader() set the size, so if that's all we needed, we're done. 71 if (onlySize) 72 return true; 105 73 106 74 // Read and process the bitmasks, if needed. 107 if (m_needToProcessBitmasks && !processBitmasks( data))75 if (m_needToProcessBitmasks && !processBitmasks()) 108 76 return false; 109 77 110 78 // Read and process the color table, if needed. 111 if (m_needToProcessColorTable && !processColorTable( data))79 if (m_needToProcessColorTable && !processColorTable()) 112 80 return false; 113 81 114 82 // Initialize the framebuffer if needed. 115 RGBA32Buffer* buffer = &m_frameBufferCache.first(); 116 if (buffer->status() == RGBA32Buffer::FrameEmpty) { 117 if (!buffer->setSize(size().width(), size().height())) { 118 // Unable to allocate. 119 setFailed(); 120 return false; 121 } 122 buffer->setStatus(RGBA32Buffer::FramePartial); 83 ASSERT(m_buffer); // Parent should set this before asking us to decode! 84 if (m_buffer->status() == RGBA32Buffer::FrameEmpty) { 85 if (!m_buffer->setSize(m_parent->size().width(), 86 m_parent->size().height())) 87 return setFailed(); // Unable to allocate. 88 m_buffer->setStatus(RGBA32Buffer::FramePartial); 123 89 // setSize() calls eraseARGB(), which resets the alpha flag, so we force 124 90 // it back to false here. We'll set it true below in all cases where 125 91 // these 0s could actually show through. 126 buffer->setHasAlpha(false);92 m_buffer->setHasAlpha(false); 127 93 128 94 // For BMPs, the frame always fills the entire image. 129 buffer->setRect(IntRect(IntPoint(),size()));95 m_buffer->setRect(IntRect(IntPoint(), m_parent->size())); 130 96 131 97 if (!m_isTopDown) 132 m_coord.setY( size().height() - 1);98 m_coord.setY(m_parent->size().height() - 1); 133 99 } 134 100 … … 138 104 || (m_infoHeader.biCompression == RLE8) 139 105 || (m_infoHeader.biCompression == RLE24)) { 140 if (!processRLEData( data))106 if (!processRLEData()) 141 107 return false; 142 } else if (!processNonRLEData( data,false, 0))108 } else if (!processNonRLEData(false, 0)) 143 109 return false; 144 110 } … … 146 112 // If the image has an AND mask and there was no alpha data, process the 147 113 // mask. 148 if ((m_andMaskState == NotYetDecoded) && ! buffer->hasAlpha()) {114 if ((m_andMaskState == NotYetDecoded) && !m_buffer->hasAlpha()) { 149 115 // Reset decoding coordinates to start of image. 150 116 m_coord.setX(0); 151 m_coord.setY(m_isTopDown ? 0 : ( size().height() - 1));117 m_coord.setY(m_isTopDown ? 0 : (m_parent->size().height() - 1)); 152 118 153 119 // The AND mask is stored as 1-bit data. … … 156 122 m_andMaskState = Decoding; 157 123 } 158 if ((m_andMaskState == Decoding) && !processNonRLEData( data,false, 0))124 if ((m_andMaskState == Decoding) && !processNonRLEData(false, 0)) 159 125 return false; 160 126 161 127 // Done! 162 buffer->setStatus(RGBA32Buffer::FrameComplete);128 m_buffer->setStatus(RGBA32Buffer::FrameComplete); 163 129 return true; 164 130 } 165 131 166 bool BMPImageReader:: getInfoHeaderSize(SharedBuffer* data)132 bool BMPImageReader::readInfoHeaderSize() 167 133 { 168 134 // Get size of info header. 169 135 ASSERT(m_decodedOffset == m_headerOffset); 170 if ((m_decodedOffset > data->size())171 || (( data->size() - m_decodedOffset) < 4))172 return false; 173 m_infoHeader.biSize = readUint32( data,0);136 if ((m_decodedOffset > m_data->size()) 137 || ((m_data->size() - m_decodedOffset) < 4)) 138 return false; 139 m_infoHeader.biSize = readUint32(0); 174 140 // Don't increment m_decodedOffset here, it just makes the code in 175 141 // processInfoHeader() more confusing. … … 180 146 if (((m_headerOffset + m_infoHeader.biSize) < m_headerOffset) 181 147 || (m_imgDataOffset 182 && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize)))) { 183 setFailed(); 184 return false; 185 } 148 && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize)))) 149 return setFailed(); 186 150 187 151 // See if this is a header size we understand: … … 197 161 || (m_infoHeader.biSize == 46))) 198 162 m_isOS22x = true; 199 else { 200 setFailed(); 201 return false; 202 } 163 else 164 return setFailed(); 203 165 204 166 return true; 205 167 } 206 168 207 bool BMPImageReader::processInfoHeader( SharedBuffer* data)169 bool BMPImageReader::processInfoHeader() 208 170 { 209 171 // Read info header. 210 172 ASSERT(m_decodedOffset == m_headerOffset); 211 if ((m_decodedOffset > data->size())212 || (( data->size() - m_decodedOffset) < m_infoHeader.biSize)213 || !readInfoHeader( data))173 if ((m_decodedOffset > m_data->size()) 174 || ((m_data->size() - m_decodedOffset) < m_infoHeader.biSize) 175 || !readInfoHeader()) 214 176 return false; 215 177 m_decodedOffset += m_infoHeader.biSize; 216 178 217 179 // Sanity-check header values. 218 if (!isInfoHeaderValid()) { 219 setFailed(); 220 return false; 221 } 222 223 // Make our size available to the caller. 224 if (!setSize(m_infoHeader.biWidth, m_infoHeader.biHeight)) { 225 setFailed(); 226 return false; 227 } 180 if (!isInfoHeaderValid()) 181 return setFailed(); 182 183 // Set our size. 184 if (!m_parent->setSize(m_infoHeader.biWidth, m_infoHeader.biHeight)) 185 return setFailed(); 228 186 229 187 // For paletted images, bitmaps can set biClrUsed to 0 to mean "all … … 255 213 } 256 214 257 bool BMPImageReader::readInfoHeader( SharedBuffer* data)215 bool BMPImageReader::readInfoHeader() 258 216 { 259 217 // Pre-initialize some fields that not all headers set. … … 262 220 263 221 if (m_isOS21x) { 264 m_infoHeader.biWidth = readUint16( data,4);265 m_infoHeader.biHeight = readUint16( data,6);222 m_infoHeader.biWidth = readUint16(4); 223 m_infoHeader.biHeight = readUint16(6); 266 224 ASSERT(m_andMaskState == None); // ICO is a Windows format, not OS/2! 267 m_infoHeader.biBitCount = readUint16( data,10);225 m_infoHeader.biBitCount = readUint16(10); 268 226 return true; 269 227 } 270 228 271 m_infoHeader.biWidth = readUint32( data,4);272 m_infoHeader.biHeight = readUint32( data,8);229 m_infoHeader.biWidth = readUint32(4); 230 m_infoHeader.biHeight = readUint32(8); 273 231 if (m_andMaskState != None) 274 232 m_infoHeader.biHeight /= 2; 275 m_infoHeader.biBitCount = readUint16( data,14);233 m_infoHeader.biBitCount = readUint16(14); 276 234 277 235 // Read compression type, if present. 278 236 if (m_infoHeader.biSize >= 20) { 279 uint32_t biCompression = readUint32( data,16);237 uint32_t biCompression = readUint32(16); 280 238 281 239 // Detect OS/2 2.x-specific compression types. … … 286 244 m_infoHeader.biCompression = RLE24; 287 245 m_isOS22x = true; 288 } else if (biCompression > 5) { 289 // Some type we don't understand. 290 setFailed(); 291 return false; 292 } else 246 } else if (biCompression > 5) 247 return setFailed(); // Some type we don't understand. 248 else 293 249 m_infoHeader.biCompression = 294 250 static_cast<CompressionType>(biCompression); … … 297 253 // Read colors used, if present. 298 254 if (m_infoHeader.biSize >= 36) 299 m_infoHeader.biClrUsed = readUint32( data,32);255 m_infoHeader.biClrUsed = readUint32(32); 300 256 301 257 // Windows V4+ can safely read the four bitmasks from 40-56 bytes in, so do … … 314 270 // processBitmasks() that doesn't always overwrite that value. 315 271 if (isWindowsV4Plus()) { 316 m_bitMasks[0] = readUint32( data,40);317 m_bitMasks[1] = readUint32( data,44);318 m_bitMasks[2] = readUint32( data,48);319 m_bitMasks[3] = readUint32( data,52);272 m_bitMasks[0] = readUint32(40); 273 m_bitMasks[1] = readUint32(44); 274 m_bitMasks[2] = readUint32(48); 275 m_bitMasks[3] = readUint32(52); 320 276 } 321 277 … … 447 403 } 448 404 449 bool BMPImageReader::processBitmasks( SharedBuffer* data)405 bool BMPImageReader::processBitmasks() 450 406 { 451 407 // Create m_bitMasks[] values. … … 479 435 (m_headerOffset + m_infoHeader.biSize)) 480 436 || (m_imgDataOffset && (m_imgDataOffset < 481 (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS)))) { 482 setFailed(); 483 return false; 484 } 437 (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS)))) 438 return setFailed(); 485 439 486 440 // Read bitmasks. 487 if (( data->size() - m_decodedOffset) < SIZEOF_BITMASKS)488 return false; 489 m_bitMasks[0] = readUint32( data,0);490 m_bitMasks[1] = readUint32( data,4);491 m_bitMasks[2] = readUint32( data,8);441 if ((m_data->size() - m_decodedOffset) < SIZEOF_BITMASKS) 442 return false; 443 m_bitMasks[0] = readUint32(0); 444 m_bitMasks[1] = readUint32(4); 445 m_bitMasks[2] = readUint32(8); 492 446 // No alpha in anything other than Windows V4+. 493 447 m_bitMasks[3] = 0; … … 522 476 // Make sure bitmask does not overlap any other bitmasks. 523 477 for (int j = 0; j < i; ++j) { 524 if (tempMask & m_bitMasks[j]) { 525 setFailed(); 526 return false; 527 } 478 if (tempMask & m_bitMasks[j]) 479 return setFailed(); 528 480 } 529 481 … … 537 489 538 490 // Make sure bitmask is contiguous. 539 if (tempMask) { 540 setFailed(); 541 return false; 542 } 491 if (tempMask) 492 return setFailed(); 543 493 544 494 // Since RGBABuffer tops out at 8 bits per channel, adjust the shift … … 553 503 } 554 504 555 bool BMPImageReader::processColorTable( SharedBuffer* data)505 bool BMPImageReader::processColorTable() 556 506 { 557 507 m_tableSizeInBytes = m_infoHeader.biClrUsed * (m_isOS21x ? 3 : 4); … … 561 511 (m_headerOffset + m_infoHeader.biSize)) 562 512 || (m_imgDataOffset && (m_imgDataOffset < 563 (m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes)))) { 564 setFailed(); 565 return false; 566 } 513 (m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes)))) 514 return setFailed(); 567 515 568 516 // Read color table. 569 if ((m_decodedOffset > data->size())570 || (( data->size() - m_decodedOffset) < m_tableSizeInBytes))517 if ((m_decodedOffset > m_data->size()) 518 || ((m_data->size() - m_decodedOffset) < m_tableSizeInBytes)) 571 519 return false; 572 520 m_colorTable.resize(m_infoHeader.biClrUsed); 573 521 for (size_t i = 0; i < m_infoHeader.biClrUsed; ++i) { 574 m_colorTable[i].rgbBlue = data->data()[m_decodedOffset++];575 m_colorTable[i].rgbGreen = data->data()[m_decodedOffset++];576 m_colorTable[i].rgbRed = data->data()[m_decodedOffset++];522 m_colorTable[i].rgbBlue = m_data->data()[m_decodedOffset++]; 523 m_colorTable[i].rgbGreen = m_data->data()[m_decodedOffset++]; 524 m_colorTable[i].rgbRed = m_data->data()[m_decodedOffset++]; 577 525 // Skip padding byte (not present on OS/2 1.x). 578 526 if (!m_isOS21x) … … 589 537 } 590 538 591 bool BMPImageReader::processRLEData( SharedBuffer* data)592 { 593 if (m_decodedOffset > data->size())539 bool BMPImageReader::processRLEData() 540 { 541 if (m_decodedOffset > m_data->size()) 594 542 return false; 595 543 … … 616 564 // Impossible to decode row-at-a-time, so just do things as a stream of 617 565 // bytes. 618 RGBA32Buffer* buffer = &m_frameBufferCache.first();619 566 while (true) { 620 567 // Every entry takes at least two bytes; bail if there isn't enough 621 568 // data. 622 if (( data->size() - m_decodedOffset) < 2)569 if ((m_data->size() - m_decodedOffset) < 2) 623 570 return false; 624 571 625 572 // For every entry except EOF, we'd better not have reached the end of 626 573 // the image. 627 const uint8_t count = data->data()[m_decodedOffset]; 628 const uint8_t code = data->data()[m_decodedOffset + 1]; 629 if (((count != 0) || (code != 1)) && pastEndOfImage(0)) { 630 setFailed(); 631 return false; 632 } 574 const uint8_t count = m_data->data()[m_decodedOffset]; 575 const uint8_t code = m_data->data()[m_decodedOffset + 1]; 576 if (((count != 0) || (code != 1)) && pastEndOfImage(0)) 577 return setFailed(); 633 578 634 579 // Decode. … … 637 582 case 0: // Magic token: EOL 638 583 // Skip any remaining pixels in this row. 639 if (m_coord.x() < size().width())640 buffer->setHasAlpha(true);584 if (m_coord.x() < m_parent->size().width()) 585 m_buffer->setHasAlpha(true); 641 586 moveBufferToNextRow(); 642 587 … … 646 591 case 1: // Magic token: EOF 647 592 // Skip any remaining pixels in the image. 648 if ((m_coord.x() < size().width())593 if ((m_coord.x() < m_parent->size().width()) 649 594 || (m_isTopDown 650 ? (m_coord.y() < ( size().height() - 1))595 ? (m_coord.y() < (m_parent->size().height() - 1)) 651 596 : (m_coord.y() > 0))) 652 buffer->setHasAlpha(true);597 m_buffer->setHasAlpha(true); 653 598 return true; 654 599 … … 656 601 // The next two bytes specify dx and dy. Bail if there isn't 657 602 // enough data. 658 if (( data->size() - m_decodedOffset) < 4)603 if ((m_data->size() - m_decodedOffset) < 4) 659 604 return false; 660 605 661 606 // Fail if this takes us past the end of the desired row or 662 607 // past the end of the image. 663 const uint8_t dx = data->data()[m_decodedOffset + 2];664 const uint8_t dy = data->data()[m_decodedOffset + 3];608 const uint8_t dx = m_data->data()[m_decodedOffset + 2]; 609 const uint8_t dy = m_data->data()[m_decodedOffset + 3]; 665 610 if ((dx != 0) || (dy != 0)) 666 buffer->setHasAlpha(true); 667 if (((m_coord.x() + dx) > size().width()) || 668 pastEndOfImage(dy)) { 669 setFailed(); 670 return false; 671 } 611 m_buffer->setHasAlpha(true); 612 if (((m_coord.x() + dx) > m_parent->size().width()) || 613 pastEndOfImage(dy)) 614 return setFailed(); 672 615 673 616 // Skip intervening pixels. … … 685 628 // the escape bytes and then reset if decoding failed. 686 629 m_decodedOffset += 2; 687 if (!processNonRLEData( data,true, code)) {630 if (!processNonRLEData(true, code)) { 688 631 m_decodedOffset -= 2; 689 632 return false; … … 695 638 // Strangely, some BMPs seem to specify excessively large counts 696 639 // here; ignore pixels past the end of the row. 697 const int endX = std::min(m_coord.x() + count, size().width()); 640 const int endX = 641 std::min(m_coord.x() + count, m_parent->size().width()); 698 642 699 643 if (m_infoHeader.biCompression == RLE24) { 700 644 // Bail if there isn't enough data. 701 if (( data->size() - m_decodedOffset) < 4)645 if ((m_data->size() - m_decodedOffset) < 4) 702 646 return false; 703 647 704 648 // One BGR triple that we copy |count| times. 705 fillRGBA(endX, data->data()[m_decodedOffset + 3],706 data->data()[m_decodedOffset + 2], code, 0xff);649 fillRGBA(endX, m_data->data()[m_decodedOffset + 3], 650 m_data->data()[m_decodedOffset + 2], code, 0xff); 707 651 m_decodedOffset += 4; 708 652 } else { … … 716 660 } 717 661 if ((colorIndexes[0] >= m_infoHeader.biClrUsed) 718 || (colorIndexes[1] >= m_infoHeader.biClrUsed)) { 719 setFailed(); 720 return false; 721 } 662 || (colorIndexes[1] >= m_infoHeader.biClrUsed)) 663 return setFailed(); 722 664 for (int which = 0; m_coord.x() < endX; ) { 723 665 setI(colorIndexes[which]); … … 731 673 } 732 674 733 bool BMPImageReader::processNonRLEData( SharedBuffer* data,bool inRLE, int numPixels)734 { 735 if (m_decodedOffset > data->size())675 bool BMPImageReader::processNonRLEData(bool inRLE, int numPixels) 676 { 677 if (m_decodedOffset > m_data->size()) 736 678 return false; 737 679 738 680 if (!inRLE) 739 numPixels = size().width();681 numPixels = m_parent->size().width(); 740 682 741 683 // Fail if we're being asked to decode more pixels than remain in the row. 742 684 const int endX = m_coord.x() + numPixels; 743 if (endX > size().width()) { 744 setFailed(); 745 return false; 746 } 685 if (endX > m_parent->size().width()) 686 return setFailed(); 747 687 748 688 // Determine how many bytes of data the requested number of pixels … … 760 700 // Decode as many rows as we can. (For RLE, where we only want to decode 761 701 // one row, we've already checked that this condition is true.) 762 RGBA32Buffer* buffer = &m_frameBufferCache.first();763 702 while (!pastEndOfImage(0)) { 764 703 // Bail if we don't have enough data for the desired number of pixels. 765 if (( data->size() - m_decodedOffset) < paddedNumBytes)704 if ((m_data->size() - m_decodedOffset) < paddedNumBytes) 766 705 return false; 767 706 … … 772 711 const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1; 773 712 for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) { 774 uint8_t pixelData = data->data()[m_decodedOffset + byte];713 uint8_t pixelData = m_data->data()[m_decodedOffset + byte]; 775 714 for (size_t pixel = 0; 776 715 (pixel < pixelsPerByte) && (m_coord.x() < endX); ++pixel) { … … 785 724 if (colorIndex) { 786 725 setRGBA(0, 0, 0, 0); 787 buffer->setHasAlpha(true);726 m_buffer->setHasAlpha(true); 788 727 } else 789 728 m_coord.move(1, 0); 790 729 } else { 791 if (colorIndex >= m_infoHeader.biClrUsed) { 792 setFailed(); 793 return false; 794 } 730 if (colorIndex >= m_infoHeader.biClrUsed) 731 return setFailed(); 795 732 setI(colorIndex); 796 733 } … … 801 738 // RGB data. Decode pixels one at a time, left to right. 802 739 while (m_coord.x() < endX) { 803 const uint32_t pixel = readCurrentPixel( data,bytesPerPixel);740 const uint32_t pixel = readCurrentPixel(bytesPerPixel); 804 741 805 742 // Some BMPs specify an alpha channel but don't actually use it … … 819 756 m_seenNonZeroAlphaPixel = true; 820 757 if (m_seenZeroAlphaPixel) { 821 buffer->zeroFill();758 m_buffer->zeroFill(); 822 759 m_seenZeroAlphaPixel = false; 823 760 } else if (alpha != 255) 824 buffer->setHasAlpha(true);761 m_buffer->setHasAlpha(true); 825 762 } 826 763 … … 846 783 } 847 784 785 bool BMPImageReader::setFailed() 786 { 787 m_parent->setFailed(); 788 m_colorTable.clear(); 789 return false; 790 } 791 848 792 } // namespace WebCore -
trunk/WebCore/platform/image-decoders/bmp/BMPImageReader.h
r44833 r44874 37 37 namespace WebCore { 38 38 39 // This class decodes a BMP image. It is used as a base for the BMP and ICO40 // decoders,which wrap it in the appropriate code to read file headers, etc.41 class BMPImageReader : public ImageDecoder{39 // This class decodes a BMP image. It is used in the BMP and ICO decoders, 40 // which wrap it in the appropriate code to read file headers, etc. 41 class BMPImageReader { 42 42 public: 43 BMPImageReader();44 45 // Does the actual decoding. |data| starts at the beginning of the file,46 // but may be incomplete.47 virtual void decodeImage(SharedBuffer* data) = 0;48 49 // ImageDecoder50 virtual void setData(SharedBuffer* data, bool allDataReceived);51 virtual RGBA32Buffer* frameBufferAtIndex(size_t index);52 53 43 // Read a value from |data[offset]|, converting from little to native 54 44 // endianness. 55 static inline uint16_t readUint16 Helper(SharedBuffer* data, int offset)45 static inline uint16_t readUint16(SharedBuffer* data, int offset) 56 46 { 57 47 uint16_t result; … … 63 53 } 64 54 65 static inline uint32_t readUint32 Helper(SharedBuffer* data, int offset)55 static inline uint32_t readUint32(SharedBuffer* data, int offset) 66 56 { 67 57 uint32_t result; … … 74 64 } 75 65 76 protected: 77 enum AndMaskState { 78 None, 79 NotYetDecoded, 80 Decoding, 81 }; 82 83 // Does the actual decoding. Returns whether decoding succeeded. 84 bool decodeBMP(SharedBuffer* data); 85 86 // An index into |m_data| representing how much we've already decoded. 87 size_t m_decodedOffset; 88 89 // The file offset at which the BMP info header starts. 90 size_t m_headerOffset; 91 92 // The file offset at which the actual image bits start. When decoding 93 // ICO files, this is set to 0, since it's not stored anywhere in a 94 // header; the reader functions expect the image data to start 95 // immediately after the header and (if necessary) color table. 96 size_t m_imgDataOffset; 97 98 // ICOs store a 1bpp "mask" immediately after the main bitmap image data 99 // (and, confusingly, add its height to the biHeight value in the info 100 // header, thus doubling it). This variable tracks whether we have such 101 // a mask and if we've started decoding it yet. 102 AndMaskState m_andMaskState; 66 // |parent| is the decoder that owns us. 67 // |startOffset| points to the start of the BMP within the file. 68 // |buffer| points at an empty RGBA32Buffer that we'll initialize and 69 // fill with decoded data. 70 BMPImageReader(ImageDecoder* parent, 71 size_t decodedAndHeaderOffset, 72 size_t imgDataOffset, 73 bool usesAndMask); 74 75 void setBuffer(RGBA32Buffer* buffer) { m_buffer = buffer; } 76 void setData(SharedBuffer* data) { m_data = data; } 77 78 // Does the actual decoding. If |onlySize| is true, decoding only 79 // progresses as far as necessary to get the image size. Returns 80 // whether decoding succeeded. 81 bool decodeBMP(bool onlySize); 103 82 104 83 private: … … 118 97 RLE24, // Stored in file as 4 119 98 }; 99 enum AndMaskState { 100 None, 101 NotYetDecoded, 102 Decoding, 103 }; 120 104 121 105 // These are based on the Windows BITMAPINFOHEADER and RGBTRIPLE … … 135 119 }; 136 120 137 inline uint16_t readUint16( SharedBuffer* data,int offset) const138 { 139 return readUint16 Helper(data, m_decodedOffset + offset);140 } 141 142 inline uint32_t readUint32( SharedBuffer* data,int offset) const143 { 144 return readUint32 Helper(data, m_decodedOffset + offset);121 inline uint16_t readUint16(int offset) const 122 { 123 return readUint16(m_data.get(), m_decodedOffset + offset); 124 } 125 126 inline uint32_t readUint32(int offset) const 127 { 128 return readUint32(m_data.get(), m_decodedOffset + offset); 145 129 } 146 130 147 131 // Determines the size of the BMP info header. Returns true if the size 148 132 // is valid. 149 bool getInfoHeaderSize(SharedBuffer* data);133 bool readInfoHeaderSize(); 150 134 151 135 // Processes the BMP info header. Returns true if the info header could 152 136 // be decoded. 153 bool processInfoHeader( SharedBuffer* data);137 bool processInfoHeader(); 154 138 155 139 // Helper function for processInfoHeader() which does the actual reading 156 140 // of header values from the byte stream. Returns false on error. 157 bool readInfoHeader( SharedBuffer* data);141 bool readInfoHeader(); 158 142 159 143 // Returns true if this is a Windows V4+ BMP. … … 170 154 // m_bitOffsets[] arrays. processInfoHeader() will initialize these for 171 155 // other compression types where needed. 172 bool processBitmasks( SharedBuffer* data);156 bool processBitmasks(); 173 157 174 158 // For paletted images, allocates and initializes the m_colorTable[] 175 159 // array. 176 bool processColorTable( SharedBuffer* data);160 bool processColorTable(); 177 161 178 162 // Processes an RLE-encoded image. Returns true if the entire image was 179 163 // decoded. 180 bool processRLEData( SharedBuffer* data);164 bool processRLEData(); 181 165 182 166 // Processes a set of non-RLE-compressed pixels. Two cases: … … 189 173 // many complete rows as possible. Returns true if the whole image 190 174 // was decoded. 191 bool processNonRLEData( SharedBuffer* data,bool inRLE, int numPixels);175 bool processNonRLEData(bool inRLE, int numPixels); 192 176 193 177 // Returns true if the current y-coordinate plus |numRows| would be past … … 197 181 { 198 182 return m_isTopDown 199 ? ((m_coord.y() + numRows) >= size().height())183 ? ((m_coord.y() + numRows) >= m_parent->size().height()) 200 184 : ((m_coord.y() - numRows) < 0); 201 185 } … … 206 190 // NOTE: Only as many bytes of the return value as are needed to hold 207 191 // the pixel data will actually be set. 208 inline uint32_t readCurrentPixel( SharedBuffer* data,int bytesPerPixel) const209 { 210 const int additionalOffset = m_coord.x() * bytesPerPixel;192 inline uint32_t readCurrentPixel(int bytesPerPixel) const 193 { 194 const int offset = m_coord.x() * bytesPerPixel; 211 195 switch (bytesPerPixel) { 212 196 case 2: 213 return readUint16( data, additionalOffset);197 return readUint16(offset); 214 198 215 199 case 3: { … … 218 202 // won't read it. 219 203 uint32_t pixel; 220 memcpy(&pixel, 221 &data->data()[m_decodedOffset + additionalOffset], 3); 204 memcpy(&pixel, &m_data->data()[m_decodedOffset + offset], 3); 222 205 #if PLATFORM(BIG_ENDIAN) 223 206 pixel = ((pixel & 0xff00) << 8) | ((pixel & 0xff0000) >> 8) | … … 228 211 229 212 case 4: 230 return readUint32( data, additionalOffset);213 return readUint32(offset); 231 214 232 215 default: … … 269 252 unsigned alpha) 270 253 { 271 m_frameBufferCache.first().setRGBA(m_coord.x(), m_coord.y(), red, green, blue, alpha); 254 m_buffer->setRGBA(m_coord.x(), m_coord.y(), red, green, blue, 255 alpha); 272 256 m_coord.move(1, 0); 273 257 } … … 291 275 // depending on the value of |m_isTopDown|. 292 276 void moveBufferToNextRow(); 277 278 // Sets the "decode failure" flag and clears any local storage. For 279 // caller convenience (since so many callers want to return false after 280 // calling this), returns false to enable easy tailcalling. 281 bool setFailed(); 282 283 // The decoder that owns us. 284 ImageDecoder* m_parent; 285 286 // The destination for the pixel data. 287 RGBA32Buffer* m_buffer; 288 289 // The file to decode. 290 RefPtr<SharedBuffer> m_data; 291 292 // An index into |m_data| representing how much we've already decoded. 293 size_t m_decodedOffset; 294 295 // The file offset at which the BMP info header starts. 296 size_t m_headerOffset; 297 298 // The file offset at which the actual image bits start. When decoding 299 // ICO files, this is set to 0, since it's not stored anywhere in a 300 // header; the reader functions expect the image data to start 301 // immediately after the header and (if necessary) color table. 302 size_t m_imgDataOffset; 293 303 294 304 // The BMP info header. … … 342 352 bool m_seenNonZeroAlphaPixel; 343 353 bool m_seenZeroAlphaPixel; 354 355 // ICOs store a 1bpp "mask" immediately after the main bitmap image data 356 // (and, confusingly, add its height to the biHeight value in the info 357 // header, thus doubling it). This variable tracks whether we have such 358 // a mask and if we've started decoding it yet. 359 AndMaskState m_andMaskState; 344 360 }; 345 361 -
trunk/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp
r44833 r44874 32 32 #include "ICOImageDecoder.h" 33 33 34 #include "BMPImageReader.h" 35 #include "PNGImageDecoder.h" 36 34 37 namespace WebCore { 35 38 … … 41 44 42 45 ICOImageDecoder::ICOImageDecoder(const IntSize& preferredIconSize) 43 : BMPImageReader() 46 : ImageDecoder() 47 , m_allDataReceived(false) 48 , m_decodedOffset(0) 44 49 , m_preferredIconSize(preferredIconSize) 45 50 , m_imageType(Unknown) 46 51 { 47 m_andMaskState = NotYetDecoded; 52 } 53 54 void ICOImageDecoder::setData(SharedBuffer* data, bool allDataReceived) 55 { 56 if (failed()) 57 return; 58 59 ImageDecoder::setData(data, allDataReceived); 60 m_allDataReceived = allDataReceived; 61 if (m_bmpReader) 62 m_bmpReader->setData(data); 63 if (m_pngDecoder) { 64 // Copy out PNG data to a separate vector and send to the PNG decoder. 65 // FIXME: Save this copy by making the PNG decoder able to take an 66 // optional offset. 67 RefPtr<SharedBuffer> pngData( 68 SharedBuffer::create(&m_data->data()[m_dirEntry.dwImageOffset], 69 m_data->size() - m_dirEntry.dwImageOffset)); 70 m_pngDecoder->setData(pngData.get(), m_allDataReceived); 71 } 48 72 } 49 73 50 74 bool ICOImageDecoder::isSizeAvailable() 51 75 { 76 if (!ImageDecoder::isSizeAvailable() && !failed()) 77 decodeWithCheckForDataEnded(true); 78 52 79 return (m_imageType == PNG) ? 53 m_pngDecoder .isSizeAvailable() : BMPImageReader::isSizeAvailable();80 m_pngDecoder->isSizeAvailable() : ImageDecoder::isSizeAvailable(); 54 81 } 55 82 56 83 IntSize ICOImageDecoder::size() const 57 84 { 58 return (m_imageType == PNG) ? m_pngDecoder.size() : BMPImageReader::size(); 59 } 60 61 void ICOImageDecoder::decodeImage(SharedBuffer* data) 85 return (m_imageType == PNG) ? m_pngDecoder->size() : ImageDecoder::size(); 86 } 87 88 RGBA32Buffer* ICOImageDecoder::frameBufferAtIndex(size_t index) 89 { 90 if (index) 91 return 0; 92 93 if (m_imageType == Unknown) 94 decodeWithCheckForDataEnded(true); 95 96 if (m_imageType == PNG) { 97 m_frameBufferCache.clear(); 98 return m_pngDecoder->frameBufferAtIndex(index); 99 } 100 101 if (m_frameBufferCache.isEmpty()) 102 m_frameBufferCache.resize(1); 103 104 RGBA32Buffer* buffer = &m_frameBufferCache.first(); 105 if (buffer->status() != RGBA32Buffer::FrameComplete && (m_imageType == BMP) 106 && !failed()) 107 decodeWithCheckForDataEnded(false); 108 return buffer; 109 } 110 111 void ICOImageDecoder::decodeWithCheckForDataEnded(bool onlySize) 112 { 113 if (failed()) 114 return; 115 116 // If we couldn't decode the image but we've received all the data, decoding 117 // has failed. 118 if (!decode(onlySize) && m_allDataReceived) 119 setFailed(); 120 } 121 122 bool ICOImageDecoder::decode(bool onlySize) 62 123 { 63 124 // Read and process directory. 64 if ((m_decodedOffset < sizeOfDirectory) && !processDirectory( data))65 return ;125 if ((m_decodedOffset < sizeOfDirectory) && !processDirectory()) 126 return false; 66 127 67 128 // Read and process directory entries. 68 129 if ((m_decodedOffset < 69 130 (sizeOfDirectory + (m_directory.idCount * sizeOfDirEntry))) 70 && !processDirectoryEntries( data))71 return ;131 && !processDirectoryEntries()) 132 return false; 72 133 73 134 // Get the image type. 74 if ((m_imageType == Unknown) && !processImageType(data)) 75 return; 76 77 // Decode selected entry. 78 if (m_imageType == PNG) 79 decodePNG(data); 80 else { 135 if ((m_imageType == Unknown) && !processImageType()) 136 return false; 137 138 // Create the appropriate image decoder if need be. 139 if ((m_imageType == PNG) ? !m_pngDecoder : !m_bmpReader) { 140 if (m_imageType == PNG) 141 m_pngDecoder.set(new PNGImageDecoder()); 142 else 143 m_bmpReader.set(new BMPImageReader(this, m_decodedOffset, 0, true)); 144 81 145 // Note that we don't try to limit the bytes we give to the decoder to 82 146 // just the size specified in the icon directory. If the size given in … … 86 150 // run out of bytes, finish decoding, or hit a sequence that makes the 87 151 // decoder fail. 88 decodeBMP(data); 89 } 90 } 91 92 RGBA32Buffer* ICOImageDecoder::frameBufferAtIndex(size_t index) 93 { 94 return (m_imageType == PNG) ? m_pngDecoder.frameBufferAtIndex(0) : 95 BMPImageReader::frameBufferAtIndex(0); 96 } 97 98 bool ICOImageDecoder::processDirectory(SharedBuffer* data) 152 setData(m_data.get(), m_allDataReceived); 153 } 154 155 // For PNGs, we're now done; further decoding will happen when calling 156 // isSizeAvailable() or frameBufferAtIndex() on the PNG decoder. 157 if (m_imageType == PNG) 158 return true; 159 160 if (!m_frameBufferCache.isEmpty()) 161 m_bmpReader->setBuffer(&m_frameBufferCache.first()); 162 163 return m_bmpReader->decodeBMP(onlySize); 164 } 165 166 bool ICOImageDecoder::processDirectory() 99 167 { 100 168 // Read directory. 101 169 ASSERT(!m_decodedOffset); 102 if ( data->size() < sizeOfDirectory)103 return false; 104 const uint16_t fileType = readUint16( data,2);105 m_directory.idCount = readUint16( data,4);170 if (m_data->size() < sizeOfDirectory) 171 return false; 172 const uint16_t fileType = readUint16(2); 173 m_directory.idCount = readUint16(4); 106 174 m_decodedOffset = sizeOfDirectory; 107 175 … … 119 187 } 120 188 121 bool ICOImageDecoder::processDirectoryEntries( SharedBuffer* data)189 bool ICOImageDecoder::processDirectoryEntries() 122 190 { 123 191 // Read directory entries. 124 192 ASSERT(m_decodedOffset == sizeOfDirectory); 125 if ((m_decodedOffset > data->size())126 || (( data->size() - m_decodedOffset) <193 if ((m_decodedOffset > m_data->size()) 194 || ((m_data->size() - m_decodedOffset) < 127 195 (m_directory.idCount * sizeOfDirEntry))) 128 196 return false; 129 197 for (int i = 0; i < m_directory.idCount; ++i) { 130 const IconDirectoryEntry dirEntry = readDirectoryEntry( data);198 const IconDirectoryEntry dirEntry = readDirectoryEntry(); 131 199 if ((i == 0) || isBetterEntry(dirEntry)) 132 200 m_dirEntry = dirEntry; … … 144 212 145 213 // Ready to decode the image at the specified offset. 146 m_decodedOffset = m_ headerOffset = m_dirEntry.dwImageOffset;214 m_decodedOffset = m_dirEntry.dwImageOffset; 147 215 return true; 148 216 } 149 217 150 ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry( 151 SharedBuffer* data) 218 ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() 152 219 { 153 220 // Read icon data. 154 221 IconDirectoryEntry entry; 155 entry.bWidth = static_cast<uint8_t>( data->data()[m_decodedOffset]);222 entry.bWidth = static_cast<uint8_t>(m_data->data()[m_decodedOffset]); 156 223 if (entry.bWidth == 0) 157 224 entry.bWidth = 256; 158 entry.bHeight = static_cast<uint8_t>( data->data()[m_decodedOffset + 1]);225 entry.bHeight = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]); 159 226 if (entry.bHeight == 0) 160 227 entry.bHeight = 256; 161 entry.wBitCount = readUint16( data,6);162 entry.dwImageOffset = readUint32( data,12);228 entry.wBitCount = readUint16(6); 229 entry.dwImageOffset = readUint32(12); 163 230 164 231 // Some icons don't have a bit depth, only a color count. Convert the … … 167 234 // this value to determine which icon entry is best. 168 235 if (!entry.wBitCount) { 169 uint8_t colorCount = data->data()[m_decodedOffset + 2];236 uint8_t colorCount = m_data->data()[m_decodedOffset + 2]; 170 237 if (colorCount) { 171 238 for (--colorCount; colorCount; colorCount >>= 1) … … 208 275 } 209 276 210 bool ICOImageDecoder::processImageType( SharedBuffer* data)277 bool ICOImageDecoder::processImageType() 211 278 { 212 279 // Check if this entry is a BMP or a PNG; we need 4 bytes to check the magic 213 280 // number. 214 281 ASSERT(m_decodedOffset == m_dirEntry.dwImageOffset); 215 if ((m_decodedOffset > data->size())216 || (( data->size() - m_decodedOffset) < 4))282 if ((m_decodedOffset > m_data->size()) 283 || ((m_data->size() - m_decodedOffset) < 4)) 217 284 return false; 218 285 m_imageType = 219 strncmp(& data->data()[m_decodedOffset], "\x89PNG", 4) ? BMP : PNG;286 strncmp(&m_data->data()[m_decodedOffset], "\x89PNG", 4) ? BMP : PNG; 220 287 return true; 221 288 } 222 289 223 void ICOImageDecoder::decodePNG(SharedBuffer* data) 224 { 225 // Copy out PNG data to a separate vector and instantiate PNG decoder. 226 // It would be nice to save this copy, if I could figure out how to just 227 // offset the perceived start of |data| by |m_dirEntry.dwImageOffset| when 228 // passing it to setData()... 229 RefPtr<SharedBuffer> pngData( 230 SharedBuffer::create(&data->data()[m_dirEntry.dwImageOffset], 231 data->size() - m_dirEntry.dwImageOffset)); 232 m_pngDecoder.setData(pngData.get(), true); 233 234 // Decode PNG as a side effect of asking for the frame. Strangely, it's 235 // seemingly unsafe to call decode() or isSizeAvailable() before calling 236 // this, as this is the only function that enlarges the framebuffer to 237 // nonzero size, and before this happens any decoded image data is silently 238 // thrown away and never decoded again (!). 239 m_pngDecoder.frameBufferAtIndex(0); 240 m_failed = m_pngDecoder.failed(); 241 242 // Sanity-check that the size is what we expected. 243 if (isSizeAvailable() && ((size().width() != m_dirEntry.bWidth) || 244 (size().height() != m_dirEntry.bHeight))) 245 m_failed = true; 246 } 247 248 } 290 } -
trunk/WebCore/platform/image-decoders/ico/ICOImageDecoder.h
r44833 r44874 33 33 34 34 #include "BMPImageReader.h" 35 #include "PNGImageDecoder.h"36 35 37 36 namespace WebCore { 38 37 38 class PNGImageDecoder; 39 39 40 // This class decodes the ICO and CUR image formats. 40 class ICOImageDecoder : public BMPImageReader {41 class ICOImageDecoder : public ImageDecoder { 41 42 public: 42 43 // See comments on |m_preferredIconSize| below. … … 45 46 // ImageDecoder 46 47 virtual String filenameExtension() const { return "ico"; } 48 virtual void setData(SharedBuffer*, bool allDataReceived); 47 49 virtual bool isSizeAvailable(); 48 50 virtual IntSize size() const; 49 50 // BMPImageReader51 virtual void decodeImage(SharedBuffer* data);52 51 virtual RGBA32Buffer* frameBufferAtIndex(size_t index); 53 52 … … 71 70 }; 72 71 73 inline uint16_t readUint16( SharedBuffer* data,int offset) const72 inline uint16_t readUint16(int offset) const 74 73 { 75 return readUint16Helper(data, m_decodedOffset + offset); 74 return BMPImageReader::readUint16(m_data.get(), 75 m_decodedOffset + offset); 76 76 } 77 77 78 inline uint32_t readUint32( SharedBuffer* data,int offset) const78 inline uint32_t readUint32(int offset) const 79 79 { 80 return readUint32Helper(data, m_decodedOffset + offset); 80 return BMPImageReader::readUint32(m_data.get(), 81 m_decodedOffset + offset); 81 82 } 83 84 // Decodes the image. If |onlySize| is true, stops decoding after 85 // calculating the image size. If decoding fails but there is no more 86 // data coming, sets the "decode failure" flag. 87 // 88 // NOTE: If the desired entry is a PNG, this doesn't actually trigger 89 // decoding, it merely ensures the decoder is created and ready to 90 // decode. The caller will then call a function on the PNGImageDecoder 91 // that actually triggers decoding. 92 void decodeWithCheckForDataEnded(bool onlySize); 93 94 // Decodes the image. If |onlySize| is true, stops decoding after 95 // calculating the image size. Returns whether decoding succeeded. 96 // NOTE: Used internally by decodeWithCheckForDataEnded(). Other people 97 // should not call this. 98 bool decode(bool onlySize); 82 99 83 100 // Processes the ICONDIR at the beginning of the data. Returns true if 84 101 // the directory could be decoded. 85 bool processDirectory( SharedBuffer*);102 bool processDirectory(); 86 103 87 104 // Processes the ICONDIRENTRY records after the directory. Keeps the 88 105 // "best" entry as the one we'll decode. Returns true if the entries 89 106 // could be decoded. 90 bool processDirectoryEntries( SharedBuffer*);107 bool processDirectoryEntries(); 91 108 92 109 // Reads and returns a directory entry from the current offset into 93 110 // |data|. 94 IconDirectoryEntry readDirectoryEntry( SharedBuffer*);111 IconDirectoryEntry readDirectoryEntry(); 95 112 96 113 // Returns true if |entry| is a preferable icon entry to m_dirEntry. … … 100 117 // Determines whether the desired entry is a BMP or PNG. Returns true 101 118 // if the type could be determined. 102 bool processImageType( SharedBuffer*);119 bool processImageType(); 103 120 104 // Called when the image to be decoded is a PNG rather than a BMP. 105 // Instantiates a PNGImageDecoder, decodes the image, and copies the 106 // results locally. 107 void decodePNG(SharedBuffer*); 121 // True if we've seen all the data. 122 bool m_allDataReceived; 123 124 // An index into |m_data| representing how much we've already decoded. 125 // Note that this only tracks data _this_ class decodes; once the 126 // BMPImageReader takes over this will not be updated further. 127 size_t m_decodedOffset; 108 128 109 129 // The entry size we should prefer. If this is empty, we choose the … … 116 136 IconDirectoryEntry m_dirEntry; 117 137 138 // The BMP reader, if we need to use one. 139 OwnPtr<BMPImageReader> m_bmpReader; 140 118 141 // The PNG decoder, if we need to use one. 119 PNGImageDecoderm_pngDecoder;142 OwnPtr<PNGImageDecoder> m_pngDecoder; 120 143 121 144 // What kind of image data is stored at the entry we're decoding.
Note: See TracChangeset
for help on using the changeset viewer.