Changeset 44874 in webkit


Ignore:
Timestamp:
Jun 19, 2009 2:49:25 PM (15 years ago)
Author:
pkasting@chromium.org
Message:

2009-06-19 Peter Kasting <pkasting@google.com>

Reviewed by Eric Seidel.

https://bugs.webkit.org/show_bug.cgi?id=26460 part three
Make BMPImageReader a standalone class that is used by ICOImageDecoder
and BMPImageDecoder to decode individual BMPs within a file. These
decoders now inherit directly from ImageDecoder.


This also makes these decoders decode on-demand in isSizeAvailable() and
frameBufferAtIndex(), like the other decoders, instead of when setData()
is called, like before. This should provide a speedup on pages
containing BMPs that aren't immediately onscreen.

  • platform/image-decoders/bmp/BMPImageDecoder.cpp: (WebCore::BMPImageDecoder::BMPImageDecoder): (WebCore::BMPImageDecoder::setData): (WebCore::BMPImageDecoder::isSizeAvailable): (WebCore::BMPImageDecoder::frameBufferAtIndex): (WebCore::BMPImageDecoder::decodeWithCheckForDataEnded): (WebCore::BMPImageDecoder::decode): (WebCore::BMPImageDecoder::processFileHeader):
  • platform/image-decoders/bmp/BMPImageDecoder.h: (WebCore::BMPImageDecoder::readUint32):
  • platform/image-decoders/bmp/BMPImageReader.cpp: (WebCore::BMPImageReader::BMPImageReader): (WebCore::BMPImageReader::decodeBMP): (WebCore::BMPImageReader::readInfoHeaderSize): (WebCore::BMPImageReader::processInfoHeader): (WebCore::BMPImageReader::readInfoHeader): (WebCore::BMPImageReader::processBitmasks): (WebCore::BMPImageReader::processColorTable): (WebCore::BMPImageReader::processRLEData): (WebCore::BMPImageReader::processNonRLEData): (WebCore::BMPImageReader::setFailed):
  • platform/image-decoders/bmp/BMPImageReader.h: (WebCore::BMPImageReader::readUint16): (WebCore::BMPImageReader::readUint32): (WebCore::BMPImageReader::setBuffer): (WebCore::BMPImageReader::setData): (WebCore::BMPImageReader::): (WebCore::BMPImageReader::pastEndOfImage): (WebCore::BMPImageReader::readCurrentPixel): (WebCore::BMPImageReader::setRGBA):
  • platform/image-decoders/ico/ICOImageDecoder.cpp: (WebCore::ICOImageDecoder::ICOImageDecoder): (WebCore::ICOImageDecoder::setData): (WebCore::ICOImageDecoder::isSizeAvailable): (WebCore::ICOImageDecoder::size): (WebCore::ICOImageDecoder::frameBufferAtIndex): (WebCore::ICOImageDecoder::decodeWithCheckForDataEnded): (WebCore::ICOImageDecoder::decode): (WebCore::ICOImageDecoder::processDirectory): (WebCore::ICOImageDecoder::processDirectoryEntries): (WebCore::ICOImageDecoder::readDirectoryEntry): (WebCore::ICOImageDecoder::processImageType):
  • platform/image-decoders/ico/ICOImageDecoder.h: (WebCore::ICOImageDecoder::readUint16): (WebCore::ICOImageDecoder::readUint32):
Location:
trunk/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r44869 r44874  
     12009-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
    1612009-06-19  Adam Barth  <abarth@webkit.org>
    262
  • trunk/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp

    r44833 r44874  
    3232#include "BMPImageDecoder.h"
    3333
     34#include "BMPImageReader.h"
     35
    3436namespace WebCore {
    3537
     
    4042
    4143BMPImageDecoder::BMPImageDecoder()
    42     : BMPImageReader()
     44    : ImageDecoder()
     45    , m_allDataReceived(false)
     46    , m_decodedOffset(0)
    4347{
    4448}
    4549
    46 void BMPImageDecoder::decodeImage(SharedBuffer* data)
     50void BMPImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
    4751{
    48     // Read and process file header.
    49     if ((m_decodedOffset < sizeOfFileHeader) && !processFileHeader(data))
     52    if (failed())
    5053        return;
    5154
    52     // Decode BMP.
    53     decodeBMP(data);
     55    ImageDecoder::setData(data, allDataReceived);
     56    m_allDataReceived = allDataReceived;
     57    if (m_reader)
     58        m_reader->setData(data);
    5459}
    5560
    56 bool BMPImageDecoder::processFileHeader(SharedBuffer* data)
     61bool BMPImageDecoder::isSizeAvailable()
    5762{
     63    if (!ImageDecoder::isSizeAvailable() && !failed())
     64        decodeWithCheckForDataEnded(true);
     65
     66    return ImageDecoder::isSizeAvailable();
     67}
     68
     69RGBA32Buffer* 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
     83void 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
     94bool 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
     113bool BMPImageDecoder::processFileHeader(size_t* imgDataOffset)
     114{
     115    ASSERT(imgDataOffset);
     116
    58117    // Read file header.
    59118    ASSERT(!m_decodedOffset);
    60     if (data->size() < sizeOfFileHeader)
     119    if (m_data->size() < sizeOfFileHeader)
    61120        return false;
    62121    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;
    66125
    67126    // See if this is a bitmap filetype we understand.
  • trunk/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h

    r44833 r44874  
    3333
    3434#include "BMPImageReader.h"
     35#include <wtf/OwnPtr.h>
    3536
    3637namespace WebCore {
    3738
    3839    // This class decodes the BMP image format.
    39     class BMPImageDecoder : public BMPImageReader {
     40    class BMPImageDecoder : public ImageDecoder {
    4041    public:
    4142        BMPImageDecoder();
    4243
     44        // ImageDecoder
    4345        virtual String filenameExtension() const { return "bmp"; }
    44 
    45         // BMPImageReader
    46         virtual void decodeImage(SharedBuffer*);
     46        virtual void setData(SharedBuffer*, bool allDataReceived);
     47        virtual bool isSizeAvailable();
     48        virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
    4749
    4850    private:
    49         inline uint32_t readUint32(SharedBuffer* data, int offset) const
     51        inline uint32_t readUint32(int offset) const
    5052        {
    51             return readUint32Helper(data, m_decodedOffset + offset);
     53            return BMPImageReader::readUint32(m_data.get(),
     54                                              m_decodedOffset + offset);
    5255        }
    5356
    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;
    5783    };
    5884
  • trunk/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp

    r44833 r44874  
    3434namespace WebCore {
    3535
    36 BMPImageReader::BMPImageReader()
    37     : m_decodedOffset(0)
    38     , m_headerOffset(0)
    39     , m_imgDataOffset(0)
    40     , m_andMaskState(None)
     36BMPImageReader::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)
    4146    , m_isOS21x(false)
    4247    , m_isOS22x(false)
     
    4853    , m_seenZeroAlphaPixel(false)
    4954{
    50     m_frameBufferCache.resize(1);
    51 
    5255    // Clue-in decodeBMP() that we need to detect the correct info header size.
    5356    memset(&m_infoHeader, 0, sizeof(m_infoHeader));
    5457}
    5558
    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)
     59bool BMPImageReader::decodeBMP(bool onlySize)
    9660{
    9761    // Calculate size of info header.
    98     if (!m_infoHeader.biSize && !getInfoHeaderSize(data))
     62    if (!m_infoHeader.biSize && !readInfoHeaderSize())
    9963        return false;
    10064
    10165    // Read and process info header.
    10266    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;
    10573
    10674    // Read and process the bitmasks, if needed.
    107     if (m_needToProcessBitmasks && !processBitmasks(data))
     75    if (m_needToProcessBitmasks && !processBitmasks())
    10876        return false;
    10977
    11078    // Read and process the color table, if needed.
    111     if (m_needToProcessColorTable && !processColorTable(data))
     79    if (m_needToProcessColorTable && !processColorTable())
    11280        return false;
    11381
    11482    // 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);
    12389        // setSize() calls eraseARGB(), which resets the alpha flag, so we force
    12490        // it back to false here.  We'll set it true below in all cases where
    12591        // these 0s could actually show through.
    126         buffer->setHasAlpha(false);
     92        m_buffer->setHasAlpha(false);
    12793
    12894        // For BMPs, the frame always fills the entire image.
    129         buffer->setRect(IntRect(IntPoint(), size()));
     95        m_buffer->setRect(IntRect(IntPoint(), m_parent->size()));
    13096
    13197        if (!m_isTopDown)
    132             m_coord.setY(size().height() - 1);
     98            m_coord.setY(m_parent->size().height() - 1);
    13399    }
    134100
     
    138104            || (m_infoHeader.biCompression == RLE8)
    139105            || (m_infoHeader.biCompression == RLE24)) {
    140             if (!processRLEData(data))
     106            if (!processRLEData())
    141107                return false;
    142         } else if (!processNonRLEData(data, false, 0))
     108        } else if (!processNonRLEData(false, 0))
    143109            return false;
    144110    }
     
    146112    // If the image has an AND mask and there was no alpha data, process the
    147113    // mask.
    148     if ((m_andMaskState == NotYetDecoded) && !buffer->hasAlpha()) {
     114    if ((m_andMaskState == NotYetDecoded) && !m_buffer->hasAlpha()) {
    149115        // Reset decoding coordinates to start of image.
    150116        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));
    152118
    153119        // The AND mask is stored as 1-bit data.
     
    156122        m_andMaskState = Decoding;
    157123    }
    158     if ((m_andMaskState == Decoding) && !processNonRLEData(data, false, 0))
     124    if ((m_andMaskState == Decoding) && !processNonRLEData(false, 0))
    159125        return false;
    160126
    161127    // Done!
    162     buffer->setStatus(RGBA32Buffer::FrameComplete);
     128    m_buffer->setStatus(RGBA32Buffer::FrameComplete);
    163129    return true;
    164130}
    165131
    166 bool BMPImageReader::getInfoHeaderSize(SharedBuffer* data)
     132bool BMPImageReader::readInfoHeaderSize()
    167133{
    168134    // Get size of info header.
    169135    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);
    174140    // Don't increment m_decodedOffset here, it just makes the code in
    175141    // processInfoHeader() more confusing.
     
    180146    if (((m_headerOffset + m_infoHeader.biSize) < m_headerOffset)
    181147        || (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();
    186150
    187151    // See if this is a header size we understand:
     
    197161                 || (m_infoHeader.biSize == 46)))
    198162        m_isOS22x = true;
    199     else {
    200         setFailed();
    201         return false;
    202     }
     163    else
     164        return setFailed();
    203165
    204166    return true;
    205167}
    206168
    207 bool BMPImageReader::processInfoHeader(SharedBuffer* data)
     169bool BMPImageReader::processInfoHeader()
    208170{
    209171    // Read info header.
    210172    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())
    214176        return false;
    215177    m_decodedOffset += m_infoHeader.biSize;
    216178
    217179    // 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();
    228186
    229187    // For paletted images, bitmaps can set biClrUsed to 0 to mean "all
     
    255213}
    256214
    257 bool BMPImageReader::readInfoHeader(SharedBuffer* data)
     215bool BMPImageReader::readInfoHeader()
    258216{
    259217    // Pre-initialize some fields that not all headers set.
     
    262220
    263221    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);
    266224        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);
    268226        return true;
    269227    }
    270228
    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);
    273231    if (m_andMaskState != None)
    274232        m_infoHeader.biHeight /= 2;
    275     m_infoHeader.biBitCount = readUint16(data, 14);
     233    m_infoHeader.biBitCount = readUint16(14);
    276234
    277235    // Read compression type, if present.
    278236    if (m_infoHeader.biSize >= 20) {
    279         uint32_t biCompression = readUint32(data, 16);
     237        uint32_t biCompression = readUint32(16);
    280238
    281239        // Detect OS/2 2.x-specific compression types.
     
    286244            m_infoHeader.biCompression = RLE24;
    287245            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
    293249            m_infoHeader.biCompression =
    294250                static_cast<CompressionType>(biCompression);
     
    297253    // Read colors used, if present.
    298254    if (m_infoHeader.biSize >= 36)
    299         m_infoHeader.biClrUsed = readUint32(data, 32);
     255        m_infoHeader.biClrUsed = readUint32(32);
    300256
    301257    // Windows V4+ can safely read the four bitmasks from 40-56 bytes in, so do
     
    314270    // processBitmasks() that doesn't always overwrite that value.
    315271    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);
    320276    }
    321277
     
    447403}
    448404
    449 bool BMPImageReader::processBitmasks(SharedBuffer* data)
     405bool BMPImageReader::processBitmasks()
    450406{
    451407    // Create m_bitMasks[] values.
     
    479435                (m_headerOffset + m_infoHeader.biSize))
    480436            || (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();
    485439
    486440        // 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);
    492446        // No alpha in anything other than Windows V4+.
    493447        m_bitMasks[3] = 0;
     
    522476        // Make sure bitmask does not overlap any other bitmasks.
    523477        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();
    528480        }
    529481
     
    537489
    538490        // Make sure bitmask is contiguous.
    539         if (tempMask) {
    540             setFailed();
    541             return false;
    542         }
     491        if (tempMask)
     492            return setFailed();
    543493
    544494        // Since RGBABuffer tops out at 8 bits per channel, adjust the shift
     
    553503}
    554504
    555 bool BMPImageReader::processColorTable(SharedBuffer* data)
     505bool BMPImageReader::processColorTable()
    556506{
    557507    m_tableSizeInBytes = m_infoHeader.biClrUsed * (m_isOS21x ? 3 : 4);
     
    561511            (m_headerOffset + m_infoHeader.biSize))
    562512        || (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();
    567515
    568516    // 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))
    571519        return false;
    572520    m_colorTable.resize(m_infoHeader.biClrUsed);
    573521    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++];
    577525        // Skip padding byte (not present on OS/2 1.x).
    578526        if (!m_isOS21x)
     
    589537}
    590538
    591 bool BMPImageReader::processRLEData(SharedBuffer* data)
    592 {
    593     if (m_decodedOffset > data->size())
     539bool BMPImageReader::processRLEData()
     540{
     541    if (m_decodedOffset > m_data->size())
    594542        return false;
    595543
     
    616564    // Impossible to decode row-at-a-time, so just do things as a stream of
    617565    // bytes.
    618     RGBA32Buffer* buffer = &m_frameBufferCache.first();
    619566    while (true) {
    620567        // Every entry takes at least two bytes; bail if there isn't enough
    621568        // data.
    622         if ((data->size() - m_decodedOffset) < 2)
     569        if ((m_data->size() - m_decodedOffset) < 2)
    623570            return false;
    624571
    625572        // For every entry except EOF, we'd better not have reached the end of
    626573        // 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();
    633578
    634579        // Decode.
     
    637582            case 0:  // Magic token: EOL
    638583                // 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);
    641586                moveBufferToNextRow();
    642587
     
    646591            case 1:  // Magic token: EOF
    647592                // Skip any remaining pixels in the image.
    648                 if ((m_coord.x() < size().width())
     593                if ((m_coord.x() < m_parent->size().width())
    649594                    || (m_isTopDown
    650                         ? (m_coord.y() < (size().height() - 1))
     595                        ? (m_coord.y() < (m_parent->size().height() - 1))
    651596                        : (m_coord.y() > 0)))
    652                     buffer->setHasAlpha(true);
     597                    m_buffer->setHasAlpha(true);
    653598                return true;
    654599
     
    656601                // The next two bytes specify dx and dy.  Bail if there isn't
    657602                // enough data.
    658                 if ((data->size() - m_decodedOffset) < 4)
     603                if ((m_data->size() - m_decodedOffset) < 4)
    659604                    return false;
    660605
    661606                // Fail if this takes us past the end of the desired row or
    662607                // 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];
    665610                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();
    672615
    673616                // Skip intervening pixels.
     
    685628                // the escape bytes and then reset if decoding failed.
    686629                m_decodedOffset += 2;
    687                 if (!processNonRLEData(data, true, code)) {
     630                if (!processNonRLEData(true, code)) {
    688631                    m_decodedOffset -= 2;
    689632                    return false;
     
    695638            // Strangely, some BMPs seem to specify excessively large counts
    696639            // 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());
    698642
    699643            if (m_infoHeader.biCompression == RLE24) {
    700644                // Bail if there isn't enough data.
    701                 if ((data->size() - m_decodedOffset) < 4)
     645                if ((m_data->size() - m_decodedOffset) < 4)
    702646                    return false;
    703647
    704648                // 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);
    707651                m_decodedOffset += 4;
    708652            } else {
     
    716660                }
    717661                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();
    722664                for (int which = 0; m_coord.x() < endX; ) {
    723665                    setI(colorIndexes[which]);
     
    731673}
    732674
    733 bool BMPImageReader::processNonRLEData(SharedBuffer* data, bool inRLE, int numPixels)
    734 {
    735     if (m_decodedOffset > data->size())
     675bool BMPImageReader::processNonRLEData(bool inRLE, int numPixels)
     676{
     677    if (m_decodedOffset > m_data->size())
    736678        return false;
    737679
    738680    if (!inRLE)
    739         numPixels = size().width();
     681        numPixels = m_parent->size().width();
    740682
    741683    // Fail if we're being asked to decode more pixels than remain in the row.
    742684    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();
    747687
    748688    // Determine how many bytes of data the requested number of pixels
     
    760700    // Decode as many rows as we can.  (For RLE, where we only want to decode
    761701    // one row, we've already checked that this condition is true.)
    762     RGBA32Buffer* buffer = &m_frameBufferCache.first();
    763702    while (!pastEndOfImage(0)) {
    764703        // 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)
    766705            return false;
    767706
     
    772711            const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1;
    773712            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];
    775714                for (size_t pixel = 0;
    776715                     (pixel < pixelsPerByte) && (m_coord.x() < endX); ++pixel) {
     
    785724                        if (colorIndex) {
    786725                            setRGBA(0, 0, 0, 0);
    787                             buffer->setHasAlpha(true);
     726                            m_buffer->setHasAlpha(true);
    788727                        } else
    789728                            m_coord.move(1, 0);
    790729                    } else {
    791                         if (colorIndex >= m_infoHeader.biClrUsed) {
    792                             setFailed();
    793                             return false;
    794                         }
     730                        if (colorIndex >= m_infoHeader.biClrUsed)
     731                            return setFailed();
    795732                        setI(colorIndex);
    796733                    }
     
    801738            // RGB data.  Decode pixels one at a time, left to right.
    802739            while (m_coord.x() < endX) {
    803                 const uint32_t pixel = readCurrentPixel(data, bytesPerPixel);
     740                const uint32_t pixel = readCurrentPixel(bytesPerPixel);
    804741
    805742                // Some BMPs specify an alpha channel but don't actually use it
     
    819756                    m_seenNonZeroAlphaPixel = true;
    820757                    if (m_seenZeroAlphaPixel) {
    821                         buffer->zeroFill();
     758                        m_buffer->zeroFill();
    822759                        m_seenZeroAlphaPixel = false;
    823760                    } else if (alpha != 255)
    824                         buffer->setHasAlpha(true);
     761                        m_buffer->setHasAlpha(true);
    825762                }
    826763
     
    846783}
    847784
     785bool BMPImageReader::setFailed()
     786{
     787    m_parent->setFailed();
     788    m_colorTable.clear();
     789    return false;
     790}
     791
    848792} // namespace WebCore
  • trunk/WebCore/platform/image-decoders/bmp/BMPImageReader.h

    r44833 r44874  
    3737namespace WebCore {
    3838
    39     // This class decodes a BMP image.  It is used as a base for the BMP and ICO
    40     // 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 {
    4242    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         // ImageDecoder
    50         virtual void setData(SharedBuffer* data, bool allDataReceived);
    51         virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
    52 
    5343        // Read a value from |data[offset]|, converting from little to native
    5444        // endianness.
    55         static inline uint16_t readUint16Helper(SharedBuffer* data, int offset)
     45        static inline uint16_t readUint16(SharedBuffer* data, int offset)
    5646        {
    5747            uint16_t result;
     
    6353        }
    6454
    65         static inline uint32_t readUint32Helper(SharedBuffer* data, int offset)
     55        static inline uint32_t readUint32(SharedBuffer* data, int offset)
    6656        {
    6757            uint32_t result;
     
    7464        }
    7565
    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);
    10382
    10483    private:
     
    11897            RLE24,      // Stored in file as 4
    11998        };
     99        enum AndMaskState {
     100            None,
     101            NotYetDecoded,
     102            Decoding,
     103        };
    120104
    121105        // These are based on the Windows BITMAPINFOHEADER and RGBTRIPLE
     
    135119        };
    136120
    137         inline uint16_t readUint16(SharedBuffer* data, int offset) const
    138         {
    139             return readUint16Helper(data, m_decodedOffset + offset);
    140         }
    141 
    142         inline uint32_t readUint32(SharedBuffer* data, int offset) const
    143         {
    144             return readUint32Helper(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);
    145129        }
    146130
    147131        // Determines the size of the BMP info header.  Returns true if the size
    148132        // is valid.
    149         bool getInfoHeaderSize(SharedBuffer* data);
     133        bool readInfoHeaderSize();
    150134
    151135        // Processes the BMP info header.  Returns true if the info header could
    152136        // be decoded.
    153         bool processInfoHeader(SharedBuffer* data);
     137        bool processInfoHeader();
    154138
    155139        // Helper function for processInfoHeader() which does the actual reading
    156140        // of header values from the byte stream.  Returns false on error.
    157         bool readInfoHeader(SharedBuffer* data);
     141        bool readInfoHeader();
    158142
    159143        // Returns true if this is a Windows V4+ BMP.
     
    170154        // m_bitOffsets[] arrays.  processInfoHeader() will initialize these for
    171155        // other compression types where needed.
    172         bool processBitmasks(SharedBuffer* data);
     156        bool processBitmasks();
    173157
    174158        // For paletted images, allocates and initializes the m_colorTable[]
    175159        // array.
    176         bool processColorTable(SharedBuffer* data);
     160        bool processColorTable();
    177161
    178162        // Processes an RLE-encoded image.  Returns true if the entire image was
    179163        // decoded.
    180         bool processRLEData(SharedBuffer* data);
     164        bool processRLEData();
    181165
    182166        // Processes a set of non-RLE-compressed pixels.  Two cases:
     
    189173        //     many complete rows as possible.  Returns true if the whole image
    190174        //     was decoded.
    191         bool processNonRLEData(SharedBuffer* data, bool inRLE, int numPixels);
     175        bool processNonRLEData(bool inRLE, int numPixels);
    192176
    193177        // Returns true if the current y-coordinate plus |numRows| would be past
     
    197181        {
    198182            return m_isTopDown
    199                 ? ((m_coord.y() + numRows) >= size().height())
     183                ? ((m_coord.y() + numRows) >= m_parent->size().height())
    200184                : ((m_coord.y() - numRows) < 0);
    201185        }
     
    206190        // NOTE: Only as many bytes of the return value as are needed to hold
    207191        // the pixel data will actually be set.
    208         inline uint32_t readCurrentPixel(SharedBuffer* data, int bytesPerPixel) const
    209         {
    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;
    211195            switch (bytesPerPixel) {
    212196            case 2:
    213                 return readUint16(data, additionalOffset);
     197                return readUint16(offset);
    214198
    215199            case 3: {
     
    218202                // won't read it.
    219203                uint32_t pixel;
    220                 memcpy(&pixel,
    221                        &data->data()[m_decodedOffset + additionalOffset], 3);
     204                memcpy(&pixel, &m_data->data()[m_decodedOffset + offset], 3);
    222205        #if PLATFORM(BIG_ENDIAN)
    223206                pixel = ((pixel & 0xff00) << 8) | ((pixel & 0xff0000) >> 8) |
     
    228211
    229212            case 4:
    230                 return readUint32(data, additionalOffset);
     213                return readUint32(offset);
    231214
    232215            default:
     
    269252                            unsigned alpha)
    270253        {
    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);
    272256            m_coord.move(1, 0);
    273257        }
     
    291275        // depending on the value of |m_isTopDown|.
    292276        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;
    293303
    294304        // The BMP info header.
     
    342352        bool m_seenNonZeroAlphaPixel;
    343353        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;
    344360    };
    345361
  • trunk/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp

    r44833 r44874  
    3232#include "ICOImageDecoder.h"
    3333
     34#include "BMPImageReader.h"
     35#include "PNGImageDecoder.h"
     36
    3437namespace WebCore {
    3538
     
    4144
    4245ICOImageDecoder::ICOImageDecoder(const IntSize& preferredIconSize)
    43     : BMPImageReader()
     46    : ImageDecoder()
     47    , m_allDataReceived(false)
     48    , m_decodedOffset(0)
    4449    , m_preferredIconSize(preferredIconSize)
    4550    , m_imageType(Unknown)
    4651{
    47     m_andMaskState = NotYetDecoded;
     52}
     53
     54void 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    }
    4872}
    4973
    5074bool ICOImageDecoder::isSizeAvailable()
    5175{
     76    if (!ImageDecoder::isSizeAvailable() && !failed())
     77        decodeWithCheckForDataEnded(true);
     78
    5279    return (m_imageType == PNG) ?
    53         m_pngDecoder.isSizeAvailable() : BMPImageReader::isSizeAvailable();
     80        m_pngDecoder->isSizeAvailable() : ImageDecoder::isSizeAvailable();
    5481}
    5582
    5683IntSize ICOImageDecoder::size() const
    5784{
    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
     88RGBA32Buffer* 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
     111void 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
     122bool ICOImageDecoder::decode(bool onlySize)
    62123{
    63124    // Read and process directory.
    64     if ((m_decodedOffset < sizeOfDirectory) && !processDirectory(data))
    65         return;
     125    if ((m_decodedOffset < sizeOfDirectory) && !processDirectory())
     126        return false;
    66127
    67128    // Read and process directory entries.
    68129    if ((m_decodedOffset <
    69130            (sizeOfDirectory + (m_directory.idCount * sizeOfDirEntry)))
    70         && !processDirectoryEntries(data))
    71         return;
     131        && !processDirectoryEntries())
     132        return false;
    72133
    73134    // 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
    81145        // Note that we don't try to limit the bytes we give to the decoder to
    82146        // just the size specified in the icon directory.  If the size given in
     
    86150        // run out of bytes, finish decoding, or hit a sequence that makes the
    87151        // 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
     166bool ICOImageDecoder::processDirectory()
    99167{
    100168    // Read directory.
    101169    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);
    106174    m_decodedOffset = sizeOfDirectory;
    107175
     
    119187}
    120188
    121 bool ICOImageDecoder::processDirectoryEntries(SharedBuffer* data)
     189bool ICOImageDecoder::processDirectoryEntries()
    122190{
    123191    // Read directory entries.
    124192    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) <
    127195            (m_directory.idCount * sizeOfDirEntry)))
    128196        return false;
    129197    for (int i = 0; i < m_directory.idCount; ++i) {
    130         const IconDirectoryEntry dirEntry = readDirectoryEntry(data);
     198        const IconDirectoryEntry dirEntry = readDirectoryEntry();
    131199        if ((i == 0) || isBetterEntry(dirEntry))
    132200            m_dirEntry = dirEntry;
     
    144212
    145213    // Ready to decode the image at the specified offset.
    146     m_decodedOffset = m_headerOffset = m_dirEntry.dwImageOffset;
     214    m_decodedOffset = m_dirEntry.dwImageOffset;
    147215    return true;
    148216}
    149217
    150 ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry(
    151     SharedBuffer* data)
     218ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry()
    152219{
    153220    // Read icon data.
    154221    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]);
    156223    if (entry.bWidth == 0)
    157224        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]);
    159226    if (entry.bHeight == 0)
    160227        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);
    163230
    164231    // Some icons don't have a bit depth, only a color count.  Convert the
     
    167234    // this value to determine which icon entry is best.
    168235    if (!entry.wBitCount) {
    169         uint8_t colorCount = data->data()[m_decodedOffset + 2];
     236        uint8_t colorCount = m_data->data()[m_decodedOffset + 2];
    170237        if (colorCount) {
    171238            for (--colorCount; colorCount; colorCount >>= 1)
     
    208275}
    209276
    210 bool ICOImageDecoder::processImageType(SharedBuffer* data)
     277bool ICOImageDecoder::processImageType()
    211278{
    212279    // Check if this entry is a BMP or a PNG; we need 4 bytes to check the magic
    213280    // number.
    214281    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))
    217284        return false;
    218285    m_imageType =
    219         strncmp(&data->data()[m_decodedOffset], "\x89PNG", 4) ? BMP : PNG;
     286        strncmp(&m_data->data()[m_decodedOffset], "\x89PNG", 4) ? BMP : PNG;
    220287    return true;
    221288}
    222289
    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  
    3333
    3434#include "BMPImageReader.h"
    35 #include "PNGImageDecoder.h"
    3635
    3736namespace WebCore {
    3837
     38    class PNGImageDecoder;
     39
    3940    // This class decodes the ICO and CUR image formats.
    40     class ICOImageDecoder : public BMPImageReader {
     41    class ICOImageDecoder : public ImageDecoder {
    4142    public:
    4243        // See comments on |m_preferredIconSize| below.
     
    4546        // ImageDecoder
    4647        virtual String filenameExtension() const { return "ico"; }
     48        virtual void setData(SharedBuffer*, bool allDataReceived);
    4749        virtual bool isSizeAvailable();
    4850        virtual IntSize size() const;
    49 
    50         // BMPImageReader
    51         virtual void decodeImage(SharedBuffer* data);
    5251        virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
    5352
     
    7170        };
    7271
    73         inline uint16_t readUint16(SharedBuffer* data, int offset) const
     72        inline uint16_t readUint16(int offset) const
    7473        {
    75             return readUint16Helper(data, m_decodedOffset + offset);
     74            return BMPImageReader::readUint16(m_data.get(),
     75                                              m_decodedOffset + offset);
    7676        }
    7777
    78         inline uint32_t readUint32(SharedBuffer* data, int offset) const
     78        inline uint32_t readUint32(int offset) const
    7979        {
    80             return readUint32Helper(data, m_decodedOffset + offset);
     80            return BMPImageReader::readUint32(m_data.get(),
     81                                              m_decodedOffset + offset);
    8182        }
     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);
    8299
    83100        // Processes the ICONDIR at the beginning of the data.  Returns true if
    84101        // the directory could be decoded.
    85         bool processDirectory(SharedBuffer*);
     102        bool processDirectory();
    86103
    87104        // Processes the ICONDIRENTRY records after the directory.  Keeps the
    88105        // "best" entry as the one we'll decode.  Returns true if the entries
    89106        // could be decoded.
    90         bool processDirectoryEntries(SharedBuffer*);
     107        bool processDirectoryEntries();
    91108
    92109        // Reads and returns a directory entry from the current offset into
    93110        // |data|.
    94         IconDirectoryEntry readDirectoryEntry(SharedBuffer*);
     111        IconDirectoryEntry readDirectoryEntry();
    95112
    96113        // Returns true if |entry| is a preferable icon entry to m_dirEntry.
     
    100117        // Determines whether the desired entry is a BMP or PNG.  Returns true
    101118        // if the type could be determined.
    102         bool processImageType(SharedBuffer*);
     119        bool processImageType();
    103120
    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;
    108128
    109129        // The entry size we should prefer.  If this is empty, we choose the
     
    116136        IconDirectoryEntry m_dirEntry;
    117137
     138        // The BMP reader, if we need to use one.
     139        OwnPtr<BMPImageReader> m_bmpReader;
     140
    118141        // The PNG decoder, if we need to use one.
    119         PNGImageDecoder m_pngDecoder;
     142        OwnPtr<PNGImageDecoder> m_pngDecoder;
    120143
    121144        // What kind of image data is stored at the entry we're decoding.
Note: See TracChangeset for help on using the changeset viewer.