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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 blink { | 67 namespace blink { |
68 | 68 |
69 BMPImageReader::BMPImageReader(ImageDecoder* parent, size_t decodedAndHeaderOffs
et, size_t imgDataOffset, bool isInICO) | 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_fastReader(nullptr) | |
73 , m_decodedOffset(decodedAndHeaderOffset) | 72 , m_decodedOffset(decodedAndHeaderOffset) |
74 , m_headerOffset(decodedAndHeaderOffset) | 73 , m_headerOffset(decodedAndHeaderOffset) |
75 , m_imgDataOffset(imgDataOffset) | 74 , m_imgDataOffset(imgDataOffset) |
76 , m_isOS21x(false) | 75 , m_isOS21x(false) |
77 , m_isOS22x(false) | 76 , m_isOS22x(false) |
78 , m_isTopDown(false) | 77 , m_isTopDown(false) |
79 , m_needToProcessBitmasks(false) | 78 , m_needToProcessBitmasks(false) |
80 , m_needToProcessColorTable(false) | 79 , m_needToProcessColorTable(false) |
81 , m_seenNonZeroAlphaPixel(false) | 80 , m_seenNonZeroAlphaPixel(false) |
82 , m_seenZeroAlphaPixel(false) | 81 , m_seenZeroAlphaPixel(false) |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 m_buffer->setPixelsChanged(true); | 159 m_buffer->setPixelsChanged(true); |
161 return (result == Failure) ? m_parent->setFailed() : (result == Success); | 160 return (result == Failure) ? m_parent->setFailed() : (result == Success); |
162 } | 161 } |
163 | 162 |
164 bool BMPImageReader::readInfoHeaderSize() | 163 bool BMPImageReader::readInfoHeaderSize() |
165 { | 164 { |
166 // Get size of info header. | 165 // Get size of info header. |
167 ASSERT(m_decodedOffset == m_headerOffset); | 166 ASSERT(m_decodedOffset == m_headerOffset); |
168 if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset
) < 4)) | 167 if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset
) < 4)) |
169 return false; | 168 return false; |
170 | |
171 m_infoHeader.biSize = readUint32(0); | 169 m_infoHeader.biSize = readUint32(0); |
172 // Don't increment m_decodedOffset here, it just makes the code in | 170 // Don't increment m_decodedOffset here, it just makes the code in |
173 // processInfoHeader() more confusing. | 171 // processInfoHeader() more confusing. |
174 | 172 |
175 // Don't allow the header to overflow (which would be harmless here, but | 173 // Don't allow the header to overflow (which would be harmless here, but |
176 // problematic or at least confusing in other places), or to overrun the | 174 // problematic or at least confusing in other places), or to overrun the |
177 // image data. | 175 // image data. |
178 const size_t headerEnd = m_headerOffset + m_infoHeader.biSize; | 176 const size_t headerEnd = m_headerOffset + m_infoHeader.biSize; |
179 if ((headerEnd < m_headerOffset) || (m_imgDataOffset && (m_imgDataOffset < h
eaderEnd))) | 177 if ((headerEnd < m_headerOffset) || (m_imgDataOffset && (m_imgDataOffset < h
eaderEnd))) |
180 return m_parent->setFailed(); | 178 return m_parent->setFailed(); |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 const size_t headerEnd = m_headerOffset + m_infoHeader.biSize; | 534 const size_t headerEnd = m_headerOffset + m_infoHeader.biSize; |
537 const size_t tableSizeInBytes = m_infoHeader.biClrUsed * (m_isOS21x ? 3 : 4)
; | 535 const size_t tableSizeInBytes = m_infoHeader.biClrUsed * (m_isOS21x ? 3 : 4)
; |
538 const size_t tableEnd = headerEnd + tableSizeInBytes; | 536 const size_t tableEnd = headerEnd + tableSizeInBytes; |
539 if ((tableEnd < headerEnd) || (m_imgDataOffset && (m_imgDataOffset < tableEn
d))) | 537 if ((tableEnd < headerEnd) || (m_imgDataOffset && (m_imgDataOffset < tableEn
d))) |
540 return m_parent->setFailed(); | 538 return m_parent->setFailed(); |
541 | 539 |
542 // Read color table. | 540 // Read color table. |
543 if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset
) < tableSizeInBytes)) | 541 if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset
) < tableSizeInBytes)) |
544 return false; | 542 return false; |
545 m_colorTable.resize(m_infoHeader.biClrUsed); | 543 m_colorTable.resize(m_infoHeader.biClrUsed); |
546 | |
547 // On non-OS/2 1.x, an extra padding byte is present, which we need to skip. | |
548 const size_t bytesPerColor = m_isOS21x ? 3 : 4; | |
549 for (size_t i = 0; i < m_infoHeader.biClrUsed; ++i) { | 544 for (size_t i = 0; i < m_infoHeader.biClrUsed; ++i) { |
550 m_colorTable[i].rgbBlue = readUint8(0); | 545 m_colorTable[i].rgbBlue = m_data->data()[m_decodedOffset++]; |
551 m_colorTable[i].rgbGreen = readUint8(1); | 546 m_colorTable[i].rgbGreen = m_data->data()[m_decodedOffset++]; |
552 m_colorTable[i].rgbRed = readUint8(2); | 547 m_colorTable[i].rgbRed = m_data->data()[m_decodedOffset++]; |
553 m_decodedOffset += bytesPerColor; | 548 // Skip padding byte (not present on OS/2 1.x). |
| 549 if (!m_isOS21x) |
| 550 ++m_decodedOffset; |
554 } | 551 } |
555 | 552 |
556 // We've now decoded all the non-image data we care about. Skip anything | 553 // We've now decoded all the non-image data we care about. Skip anything |
557 // else before the actual raster data. | 554 // else before the actual raster data. |
558 if (m_imgDataOffset) | 555 if (m_imgDataOffset) |
559 m_decodedOffset = m_imgDataOffset; | 556 m_decodedOffset = m_imgDataOffset; |
560 m_needToProcessColorTable = false; | 557 m_needToProcessColorTable = false; |
561 | 558 |
562 return true; | 559 return true; |
563 } | 560 } |
(...skipping 26 matching lines...) Expand all Loading... |
590 // Impossible to decode row-at-a-time, so just do things as a stream of | 587 // Impossible to decode row-at-a-time, so just do things as a stream of |
591 // bytes. | 588 // bytes. |
592 while (true) { | 589 while (true) { |
593 // Every entry takes at least two bytes; bail if there isn't enough | 590 // Every entry takes at least two bytes; bail if there isn't enough |
594 // data. | 591 // data. |
595 if ((m_data->size() - m_decodedOffset) < 2) | 592 if ((m_data->size() - m_decodedOffset) < 2) |
596 return InsufficientData; | 593 return InsufficientData; |
597 | 594 |
598 // For every entry except EOF, we'd better not have reached the end of | 595 // For every entry except EOF, we'd better not have reached the end of |
599 // the image. | 596 // the image. |
600 const uint8_t count = readUint8(0); | 597 const uint8_t count = m_data->data()[m_decodedOffset]; |
601 const uint8_t code = readUint8(1); | 598 const uint8_t code = m_data->data()[m_decodedOffset + 1]; |
602 if ((count || (code != 1)) && pastEndOfImage(0)) | 599 if ((count || (code != 1)) && pastEndOfImage(0)) |
603 return Failure; | 600 return Failure; |
604 | 601 |
605 // Decode. | 602 // Decode. |
606 if (!count) { | 603 if (!count) { |
607 switch (code) { | 604 switch (code) { |
608 case 0: // Magic token: EOL | 605 case 0: // Magic token: EOL |
609 // Skip any remaining pixels in this row. | 606 // Skip any remaining pixels in this row. |
610 if (m_coord.x() < m_parent->size().width()) | 607 if (m_coord.x() < m_parent->size().width()) |
611 m_buffer->setHasAlpha(true); | 608 m_buffer->setHasAlpha(true); |
(...skipping 13 matching lines...) Expand all Loading... |
625 return Success; | 622 return Success; |
626 | 623 |
627 case 2: { // Magic token: Delta | 624 case 2: { // Magic token: Delta |
628 // The next two bytes specify dx and dy. Bail if there isn't | 625 // The next two bytes specify dx and dy. Bail if there isn't |
629 // enough data. | 626 // enough data. |
630 if ((m_data->size() - m_decodedOffset) < 4) | 627 if ((m_data->size() - m_decodedOffset) < 4) |
631 return InsufficientData; | 628 return InsufficientData; |
632 | 629 |
633 // Fail if this takes us past the end of the desired row or | 630 // Fail if this takes us past the end of the desired row or |
634 // past the end of the image. | 631 // past the end of the image. |
635 const uint8_t dx = readUint8(2); | 632 const uint8_t dx = m_data->data()[m_decodedOffset + 2]; |
636 const uint8_t dy = readUint8(3); | 633 const uint8_t dy = m_data->data()[m_decodedOffset + 3]; |
637 if (dx || dy) | 634 if (dx || dy) |
638 m_buffer->setHasAlpha(true); | 635 m_buffer->setHasAlpha(true); |
639 if (((m_coord.x() + dx) > m_parent->size().width()) || pastEndOf
Image(dy)) | 636 if (((m_coord.x() + dx) > m_parent->size().width()) || pastEndOf
Image(dy)) |
640 return Failure; | 637 return Failure; |
641 | 638 |
642 // Skip intervening pixels. | 639 // Skip intervening pixels. |
643 m_coord.move(dx, m_isTopDown ? dy : -dy); | 640 m_coord.move(dx, m_isTopDown ? dy : -dy); |
644 | 641 |
645 m_decodedOffset += 4; | 642 m_decodedOffset += 4; |
646 break; | 643 break; |
(...skipping 19 matching lines...) Expand all Loading... |
666 // Strangely, some BMPs seem to specify excessively large counts | 663 // Strangely, some BMPs seem to specify excessively large counts |
667 // here; ignore pixels past the end of the row. | 664 // here; ignore pixels past the end of the row. |
668 const int endX = std::min(m_coord.x() + count, m_parent->size().widt
h()); | 665 const int endX = std::min(m_coord.x() + count, m_parent->size().widt
h()); |
669 | 666 |
670 if (m_infoHeader.biCompression == RLE24) { | 667 if (m_infoHeader.biCompression == RLE24) { |
671 // Bail if there isn't enough data. | 668 // Bail if there isn't enough data. |
672 if ((m_data->size() - m_decodedOffset) < 4) | 669 if ((m_data->size() - m_decodedOffset) < 4) |
673 return InsufficientData; | 670 return InsufficientData; |
674 | 671 |
675 // One BGR triple that we copy |count| times. | 672 // One BGR triple that we copy |count| times. |
676 fillRGBA(endX, readUint8(3), readUint8(2), code, 0xff); | 673 fillRGBA(endX, m_data->data()[m_decodedOffset + 3], m_data->data
()[m_decodedOffset + 2], code, 0xff); |
677 m_decodedOffset += 4; | 674 m_decodedOffset += 4; |
678 } else { | 675 } else { |
679 // RLE8 has one color index that gets repeated; RLE4 has two | 676 // RLE8 has one color index that gets repeated; RLE4 has two |
680 // color indexes in the upper and lower 4 bits of the byte, | 677 // color indexes in the upper and lower 4 bits of the byte, |
681 // which are alternated. | 678 // which are alternated. |
682 size_t colorIndexes[2] = {code, code}; | 679 size_t colorIndexes[2] = {code, code}; |
683 if (m_infoHeader.biCompression == RLE4) { | 680 if (m_infoHeader.biCompression == RLE4) { |
684 colorIndexes[0] = (colorIndexes[0] >> 4) & 0xf; | 681 colorIndexes[0] = (colorIndexes[0] >> 4) & 0xf; |
685 colorIndexes[1] &= 0xf; | 682 colorIndexes[1] &= 0xf; |
686 } | 683 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
729 // Bail if we don't have enough data for the desired number of pixels. | 726 // Bail if we don't have enough data for the desired number of pixels. |
730 if ((m_data->size() - m_decodedOffset) < paddedNumBytes) | 727 if ((m_data->size() - m_decodedOffset) < paddedNumBytes) |
731 return InsufficientData; | 728 return InsufficientData; |
732 | 729 |
733 if (m_infoHeader.biBitCount < 16) { | 730 if (m_infoHeader.biBitCount < 16) { |
734 // Paletted data. Pixels are stored little-endian within bytes. | 731 // Paletted data. Pixels are stored little-endian within bytes. |
735 // Decode pixels one byte at a time, left to right (so, starting at | 732 // Decode pixels one byte at a time, left to right (so, starting at |
736 // the most significant bits in the byte). | 733 // the most significant bits in the byte). |
737 const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1; | 734 const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1; |
738 for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) { | 735 for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) { |
739 uint8_t pixelData = readUint8(byte); | 736 uint8_t pixelData = m_data->data()[m_decodedOffset + byte]; |
740 for (size_t pixel = 0; (pixel < pixelsPerByte) && (m_coord.x() <
endX); ++pixel) { | 737 for (size_t pixel = 0; (pixel < pixelsPerByte) && (m_coord.x() <
endX); ++pixel) { |
741 const size_t colorIndex = (pixelData >> (8 - m_infoHeader.bi
BitCount)) & mask; | 738 const size_t colorIndex = (pixelData >> (8 - m_infoHeader.bi
BitCount)) & mask; |
742 if (m_decodingAndMask) { | 739 if (m_decodingAndMask) { |
743 // There's no way to accurately represent an AND + XOR | 740 // There's no way to accurately represent an AND + XOR |
744 // operation as an RGBA image, so where the AND values | 741 // operation as an RGBA image, so where the AND values |
745 // are 1, we simply set the framebuffer pixels to fully | 742 // are 1, we simply set the framebuffer pixels to fully |
746 // transparent, on the assumption that most ICOs on the | 743 // transparent, on the assumption that most ICOs on the |
747 // web will not be doing a lot of inverting. | 744 // web will not be doing a lot of inverting. |
748 if (colorIndex) { | 745 if (colorIndex) { |
749 setRGBA(0, 0, 0, 0); | 746 setRGBA(0, 0, 0, 0); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 // Finished decoding whole image. | 799 // Finished decoding whole image. |
803 return Success; | 800 return Success; |
804 } | 801 } |
805 | 802 |
806 void BMPImageReader::moveBufferToNextRow() | 803 void BMPImageReader::moveBufferToNextRow() |
807 { | 804 { |
808 m_coord.move(-m_coord.x(), m_isTopDown ? 1 : -1); | 805 m_coord.move(-m_coord.x(), m_isTopDown ? 1 : -1); |
809 } | 806 } |
810 | 807 |
811 } // namespace blink | 808 } // namespace blink |
OLD | NEW |