Changeset 46807 in webkit


Ignore:
Timestamp:
Aug 5, 2009 12:36:34 PM (15 years ago)
Author:
pkasting@chromium.org
Message:

2009-08-05 Peter Kasting <pkasting@google.com>

Reviewed by Eric Seidel.

https://bugs.webkit.org/show_bug.cgi?id=26460
Return multiple icon entries from the ICO decoder as separate frames,
sorted by decreasing quality (much like the CG ICO decoder does).

As a result of this change, we can eliminate the Skia-specific setData()
hack that the Chromium port used to select the desired icon size -- now
callers can just enumerate the frames and ask for the data from the one
they like.


Under the hood, the ICO decoder now keeps vectors for a number of things
(including directory entries and image decoders) where it used to have
single members. However, callers (that I have seen) will only request
one frame from the icon, so practically there aren't going to be lots of
instantiated image decoders.

  • platform/graphics/ImageSource.h: Move |m_decoder| back to private now that Skia no longer needs to access it.
  • platform/graphics/cairo/ImageSourceCairo.cpp: (WebCore::createDecoder): Remove size argument from ICO decoder instantiation.
  • platform/graphics/skia/ImageSourceSkia.cpp: (WebCore::createDecoder): Remove size argument from ICO decoder instantiation. (WebCore::ImageSource::setData): Remove function to ask for a particular icon size.
  • platform/graphics/skia/ImageSourceSkia.h: Removed.
  • platform/graphics/wx/ImageSourceWx.cpp: (WebCore::createDecoder): Remove size argument from ICO decoder instantiation.
  • platform/image-decoders/ico/ICOImageDecoder.cpp: (WebCore::ICOImageDecoder::ICOImageDecoder): (WebCore::ICOImageDecoder::~ICOImageDecoder): Delete all instantiated per-frame decoders. (WebCore::ICOImageDecoder::setData): Send data to all instantiated per-frame decoders. (WebCore::ICOImageDecoder::isSizeAvailable): Use size from icon directory instead of PNG decoder (if applicable) so we can report it without decoding the PNG frames. (WebCore::ICOImageDecoder::size): Report frame-specific size if BMP decoder is calling. Otherwise, use size from icon directory instead of PNG decoder (if applicable). (WebCore::ICOImageDecoder::frameSizeAtIndex): Implement. (WebCore::ICOImageDecoder::setSize): Sanity check value if BMP decoder is calling. (WebCore::ICOImageDecoder::frameCount): Implement. (WebCore::ICOImageDecoder::frameBufferAtIndex): Sanity check size for PNG frames. (WebCore::ICOImageDecoder::compareEntries): Add utility function for sorting entries. (WebCore::ICOImageDecoder::setDataForPNGDecoderAtIndex): Factor out utility function for passing correct data blob to a PNG decoder. (WebCore::ICOImageDecoder::decodeWithCheckForDataEnded): Split decode() into two pieces. (WebCore::ICOImageDecoder::decodeDirectory): The first part of the old decode(). (WebCore::ICOImageDecoder::decodeAtIndex): The second part of the old decode(), split off so we avoid decoding an entry until it's requested. (WebCore::ICOImageDecoder::processDirectory): Add resizing of internal data structures based on directory contents. (WebCore::ICOImageDecoder::processDirectoryEntries): Sort entries by quality. (WebCore::ICOImageDecoder::imageTypeAtIndex): Return type to caller instead of setting a member.
  • platform/image-decoders/ico/ICOImageDecoder.h:
Location:
trunk/WebCore
Files:
1 deleted
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r46806 r46807  
     12009-08-05  Peter Kasting  <pkasting@google.com>
     2
     3        Reviewed by Eric Seidel.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=26460
     6        Return multiple icon entries from the ICO decoder as separate frames,
     7        sorted by decreasing quality (much like the CG ICO decoder does).
     8
     9        As a result of this change, we can eliminate the Skia-specific setData()
     10        hack that the Chromium port used to select the desired icon size -- now
     11        callers can just enumerate the frames and ask for the data from the one
     12        they like.
     13       
     14        Under the hood, the ICO decoder now keeps vectors for a number of things
     15        (including directory entries and image decoders) where it used to have
     16        single members.  However, callers (that I have seen) will only request
     17        one frame from the icon, so practically there aren't going to be lots of
     18        instantiated image decoders.
     19
     20        * platform/graphics/ImageSource.h: Move |m_decoder| back to private now that Skia no longer needs to access it.
     21        * platform/graphics/cairo/ImageSourceCairo.cpp:
     22        (WebCore::createDecoder): Remove size argument from ICO decoder instantiation.
     23        * platform/graphics/skia/ImageSourceSkia.cpp:
     24        (WebCore::createDecoder): Remove size argument from ICO decoder instantiation.
     25        (WebCore::ImageSource::setData): Remove function to ask for a particular icon size.
     26        * platform/graphics/skia/ImageSourceSkia.h: Removed.
     27        * platform/graphics/wx/ImageSourceWx.cpp:
     28        (WebCore::createDecoder): Remove size argument from ICO decoder instantiation.
     29        * platform/image-decoders/ico/ICOImageDecoder.cpp:
     30        (WebCore::ICOImageDecoder::ICOImageDecoder):
     31        (WebCore::ICOImageDecoder::~ICOImageDecoder): Delete all instantiated per-frame decoders.
     32        (WebCore::ICOImageDecoder::setData): Send data to all instantiated per-frame decoders.
     33        (WebCore::ICOImageDecoder::isSizeAvailable): Use size from icon directory instead of PNG decoder (if applicable) so we can report it without decoding the PNG frames.
     34        (WebCore::ICOImageDecoder::size): Report frame-specific size if BMP decoder is calling.  Otherwise, use size from icon directory instead of PNG decoder (if applicable).
     35        (WebCore::ICOImageDecoder::frameSizeAtIndex): Implement.
     36        (WebCore::ICOImageDecoder::setSize): Sanity check value if BMP decoder is calling.
     37        (WebCore::ICOImageDecoder::frameCount): Implement.
     38        (WebCore::ICOImageDecoder::frameBufferAtIndex): Sanity check size for PNG frames.
     39        (WebCore::ICOImageDecoder::compareEntries): Add utility function for sorting entries.
     40        (WebCore::ICOImageDecoder::setDataForPNGDecoderAtIndex): Factor out utility function for passing correct data blob to a PNG decoder.
     41        (WebCore::ICOImageDecoder::decodeWithCheckForDataEnded): Split decode() into two pieces.
     42        (WebCore::ICOImageDecoder::decodeDirectory): The first part of the old decode().
     43        (WebCore::ICOImageDecoder::decodeAtIndex): The second part of the old decode(), split off so we avoid decoding an entry until it's requested.
     44        (WebCore::ICOImageDecoder::processDirectory): Add resizing of internal data structures based on directory contents.
     45        (WebCore::ICOImageDecoder::processDirectoryEntries): Sort entries by quality.
     46        (WebCore::ICOImageDecoder::imageTypeAtIndex): Return type to caller instead of setting a member.
     47        * platform/image-decoders/ico/ICOImageDecoder.h:
     48
    1492009-08-05  Szabo Carol  <carol.szabo@nokia.com>
    250
  • trunk/WebCore/platform/graphics/ImageSource.h

    r46590 r46807  
    143143    bool frameIsCompleteAtIndex(size_t); // Whether or not the frame is completely decoded.
    144144
    145     // FIXME: This is protected only to allow ImageSourceSkia to set ICO decoder
    146     // with a preferred size. See ImageSourceSkia.h for discussion.
    147 protected:
     145private:
    148146    NativeImageSourcePtr m_decoder;
    149147};
  • trunk/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp

    r46738 r46807  
    7676    if (!memcmp(contents, "\000\000\001\000", 4) ||
    7777        !memcmp(contents, "\000\000\002\000", 4))
    78         return new ICOImageDecoder(IntSize());
     78        return new ICOImageDecoder();
    7979
    8080    // XBMs require 8 bytes of info.
  • trunk/WebCore/platform/graphics/skia/ImageSourceSkia.cpp

    r46738 r46807  
    3131
    3232#include "config.h"
    33 #include "ImageSourceSkia.h"
     33#include "ImageSource.h"
    3434#include "SharedBuffer.h"
    3535
     
    4545namespace WebCore {
    4646
    47 ImageDecoder* createDecoder(const Vector<char>& data, const IntSize& preferredIconSize)
     47ImageDecoder* createDecoder(const Vector<char>& data)
    4848{
    4949    // We need at least 4 bytes to figure out what kind of image we're dealing with.
     
    8080    if (!memcmp(contents, "\000\000\001\000", 4) ||
    8181        !memcmp(contents, "\000\000\002\000", 4))
    82         return new ICOImageDecoder(preferredIconSize);
     82        return new ICOImageDecoder();
    8383   
    8484    // XBMs require 8 bytes of info.
     
    125125    // made.
    126126    if (!m_decoder)
    127         m_decoder = createDecoder(data->buffer(), IntSize());
     127        m_decoder = createDecoder(data->buffer());
    128128
    129129    // CreateDecoder will return NULL if the decoder could not be created. Plus,
     
    231231}
    232232
    233 void ImageSourceSkia::setData(SharedBuffer* data,
    234                               bool allDataReceived,
    235                               const IntSize& preferredIconSize)
    236 {
    237     if (!m_decoder)
    238         m_decoder = createDecoder(data->buffer(), preferredIconSize);
    239 
    240     ImageSource::setData(data, allDataReceived);
    241 }
    242 
    243233String ImageSource::filenameExtension() const
    244234{
  • trunk/WebCore/platform/graphics/wx/ImageSourceWx.cpp

    r46738 r46807  
    8181    if (!memcmp(contents, "\000\000\001\000", 4) ||
    8282        !memcmp(contents, "\000\000\002\000", 4))
    83         return new ICOImageDecoder(IntSize());
     83        return new ICOImageDecoder();
    8484   
    8585    // XBMs require 8 bytes of info.
  • trunk/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp

    r44874 r46807  
    3232#include "ICOImageDecoder.h"
    3333
     34#include <algorithm>
     35
    3436#include "BMPImageReader.h"
    3537#include "PNGImageDecoder.h"
     
    4345static const size_t sizeOfDirEntry = 16;
    4446
    45 ICOImageDecoder::ICOImageDecoder(const IntSize& preferredIconSize)
     47ICOImageDecoder::ICOImageDecoder()
    4648    : ImageDecoder()
    4749    , m_allDataReceived(false)
    4850    , m_decodedOffset(0)
    49     , m_preferredIconSize(preferredIconSize)
    50     , m_imageType(Unknown)
    51 {
     51{
     52}
     53
     54ICOImageDecoder::~ICOImageDecoder()
     55{
     56    deleteAllValues(m_bmpReaders);
     57    deleteAllValues(m_pngDecoders);
    5258}
    5359
     
    5965    ImageDecoder::setData(data, allDataReceived);
    6066    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     }
     67
     68    for (BMPReaders::iterator i(m_bmpReaders.begin());
     69         i != m_bmpReaders.end(); ++i) {
     70        if (*i)
     71            (*i)->setData(data);
     72    }
     73    for (size_t i = 0; i < m_pngDecoders.size(); ++i)
     74        setDataForPNGDecoderAtIndex(i);
    7275}
    7376
    7477bool ICOImageDecoder::isSizeAvailable()
    7578{
    76     if (!ImageDecoder::isSizeAvailable() && !failed())
    77         decodeWithCheckForDataEnded(true);
    78 
    79     return (m_imageType == PNG) ?
    80         m_pngDecoder->isSizeAvailable() : ImageDecoder::isSizeAvailable();
     79    if (!ImageDecoder::isSizeAvailable())
     80        decodeWithCheckForDataEnded(0, true);
     81
     82    return ImageDecoder::isSizeAvailable();
    8183}
    8284
    8385IntSize ICOImageDecoder::size() const
    8486{
    85     return (m_imageType == PNG) ? m_pngDecoder->size() : ImageDecoder::size();
     87    return m_frameSize.isEmpty() ? ImageDecoder::size() : m_frameSize;
     88}
     89
     90IntSize ICOImageDecoder::frameSizeAtIndex(size_t index) const
     91{
     92    return (index && (index < m_dirEntries.size())) ?
     93        m_dirEntries[index].m_size : size();
     94}
     95
     96bool ICOImageDecoder::setSize(unsigned width, unsigned height)
     97{
     98    if (m_frameSize.isEmpty())
     99        return ImageDecoder::setSize(width, height);
     100
     101    // The size calculated inside the BMPImageReader had better match the one in
     102    // the icon directory.
     103    if ((width != m_frameSize.width()) || (height != m_frameSize.height()))
     104        setFailed();
     105    return !failed();
     106}
     107
     108size_t ICOImageDecoder::frameCount()
     109{
     110    decodeWithCheckForDataEnded(0, true);
     111    if (m_frameBufferCache.isEmpty())
     112        m_frameBufferCache.resize(m_dirEntries.size());
     113    // CAUTION: We must not resize m_frameBufferCache again after this, as
     114    // decodeAtIndex() may give a BMPImageReader a pointer to one of the
     115    // entries.
     116    return m_frameBufferCache.size();
    86117}
    87118
    88119RGBA32Buffer* ICOImageDecoder::frameBufferAtIndex(size_t index)
    89120{
    90     if (index)
     121    // Ensure |index| is valid.
     122    if (index >= frameCount())
    91123        return 0;
    92124
    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)
     125    // Determine the image type, and if this is a BMP, decode.
     126    decodeWithCheckForDataEnded(index, false);
     127
     128    // PNGs decode into their own framebuffers, so only use our internal cache
     129    // for non-PNGs (BMP or unknown).
     130    if (!m_pngDecoders[index])
     131        return &m_frameBufferCache[index];
     132
     133    // Fail if the size the PNGImageDecoder calculated does not match the size
     134    // in the directory.
     135    if (m_pngDecoders[index]->isSizeAvailable()) {
     136        const IntSize pngSize(m_pngDecoders[index]->size());
     137        const IconDirectoryEntry& dirEntry = m_dirEntries[index];
     138        if (pngSize != dirEntry.m_size) {
     139            setFailed();
     140            m_pngDecoders[index]->setFailed();
     141        }
     142    }
     143
     144    return m_pngDecoders[index]->frameBufferAtIndex(0);
     145}
     146
     147// static
     148bool ICOImageDecoder::compareEntries(const IconDirectoryEntry& a,
     149                                     const IconDirectoryEntry& b)
     150{
     151    // Larger icons are better.
     152    const int aEntryArea = a.m_size.width() * a.m_size.height();
     153    const int bEntryArea = b.m_size.width() * b.m_size.height();
     154    if (aEntryArea != bEntryArea)
     155        return (aEntryArea > bEntryArea);
     156
     157    // Higher bit-depth icons are better.
     158    return (a.m_bitCount > b.m_bitCount);
     159}
     160
     161void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index)
     162{
     163    if (!m_pngDecoders[index])
     164        return;
     165
     166    const IconDirectoryEntry& dirEntry = m_dirEntries[index];
     167    // Copy out PNG data to a separate vector and send to the PNG decoder.
     168    // FIXME: Save this copy by making the PNG decoder able to take an
     169    // optional offset.
     170    RefPtr<SharedBuffer> pngData(
     171        SharedBuffer::create(&m_data->data()[dirEntry.m_imageOffset],
     172                             m_data->size() - dirEntry.m_imageOffset));
     173    m_pngDecoders[index]->setData(pngData.get(), m_allDataReceived);
     174}
     175
     176void ICOImageDecoder::decodeWithCheckForDataEnded(size_t index, bool onlySize)
    112177{
    113178    if (failed())
     
    116181    // If we couldn't decode the image but we've received all the data, decoding
    117182    // has failed.
    118     if (!decode(onlySize) && m_allDataReceived)
     183    if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index)))
     184        && m_allDataReceived)
    119185        setFailed();
    120186}
    121187
    122 bool ICOImageDecoder::decode(bool onlySize)
     188bool ICOImageDecoder::decodeDirectory()
    123189{
    124190    // Read and process directory.
     
    127193
    128194    // Read and process directory entries.
    129     if ((m_decodedOffset <
    130             (sizeOfDirectory + (m_directory.idCount * sizeOfDirEntry)))
    131         && !processDirectoryEntries())
    132         return false;
    133 
    134     // Get the image type.
    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 
    145         // Note that we don't try to limit the bytes we give to the decoder to
    146         // just the size specified in the icon directory.  If the size given in
    147         // the directory is insufficient to decode the whole image, the image is
    148         // corrupt anyway, so whatever we do may be wrong.  The easiest choice
    149         // (which we do here) is to simply aggressively consume bytes until we
    150         // run out of bytes, finish decoding, or hit a sequence that makes the
    151         // decoder fail.
    152         setData(m_data.get(), m_allDataReceived);
     195    return (m_decodedOffset >=
     196            (sizeOfDirectory + (m_dirEntries.size() * sizeOfDirEntry)))
     197        || processDirectoryEntries();
     198}
     199
     200bool ICOImageDecoder::decodeAtIndex(size_t index)
     201{
     202    ASSERT(index < m_dirEntries.size());
     203    const IconDirectoryEntry& dirEntry = m_dirEntries[index];
     204    if (!m_bmpReaders[index] && !m_pngDecoders[index]) {
     205        // Image type unknown.
     206        const ImageType imageType = imageTypeAtIndex(index);
     207        if (imageType == BMP) {
     208            // We need to have already sized m_frameBufferCache before this, and
     209            // we must not resize it again later (see caution in frameCount()).
     210            ASSERT(m_frameBufferCache.size() == m_dirEntries.size());
     211            m_bmpReaders[index] =
     212                new BMPImageReader(this, dirEntry.m_imageOffset, 0, true);
     213            m_bmpReaders[index]->setData(m_data.get());
     214            m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]);
     215        } else if (imageType == PNG) {
     216            m_pngDecoders[index] = new PNGImageDecoder();
     217            setDataForPNGDecoderAtIndex(index);
     218        } else {
     219            // Not enough data to determine image type yet.
     220            return false;
     221        }
     222    }
     223
     224    if (m_bmpReaders[index]) {
     225        m_frameSize = dirEntry.m_size;
     226        bool result = m_bmpReaders[index]->decodeBMP(false);
     227        m_frameSize = IntSize();
     228        return result;
    153229    }
    154230
    155231    // 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);
     232    // frameBufferAtIndex() on the PNG decoder.
     233    return true;
    164234}
    165235
     
    171241        return false;
    172242    const uint16_t fileType = readUint16(2);
    173     m_directory.idCount = readUint16(4);
     243    const uint16_t idCount = readUint16(4);
    174244    m_decodedOffset = sizeOfDirectory;
    175245
     
    180250        CURSOR = 2,
    181251    };
    182     if (((fileType != ICON) && (fileType != CURSOR)) ||
    183             (m_directory.idCount == 0))
     252    if (((fileType != ICON) && (fileType != CURSOR)) || (idCount == 0)) {
    184253        setFailed();
    185 
    186     return !failed();
     254        return false;
     255    }
     256
     257    // Enlarge member vectors to hold all the entries.  We must initialize the
     258    // BMP and PNG decoding vectors to 0 so that all entries can be safely
     259    // deleted in our destructor.  If we don't do this, they'll contain garbage
     260    // values, and deleting those will corrupt memory.
     261    m_dirEntries.resize(idCount);
     262    m_bmpReaders.fill(0, idCount);
     263    m_pngDecoders.fill(0, idCount);
     264    return true;
    187265}
    188266
     
    193271    if ((m_decodedOffset > m_data->size())
    194272        || ((m_data->size() - m_decodedOffset) <
    195             (m_directory.idCount * sizeOfDirEntry)))
     273            (m_dirEntries.size() * sizeOfDirEntry)))
    196274        return false;
    197     for (int i = 0; i < m_directory.idCount; ++i) {
    198         const IconDirectoryEntry dirEntry = readDirectoryEntry();
    199         if ((i == 0) || isBetterEntry(dirEntry))
    200             m_dirEntry = dirEntry;
    201     }
    202 
    203     // Make sure the specified image offset is past the end of the directory
    204     // entries, and that the offset isn't so large that it overflows when we add
    205     // 4 bytes to it (which we do in decodeImage() while ensuring it's safe to
    206     // examine the first 4 bytes of the image data).
    207     if ((m_dirEntry.dwImageOffset < m_decodedOffset) ||
    208             ((m_dirEntry.dwImageOffset + 4) < m_dirEntry.dwImageOffset)) {
    209       setFailed();
    210       return false;
    211     }
    212 
    213     // Ready to decode the image at the specified offset.
    214     m_decodedOffset = m_dirEntry.dwImageOffset;
     275    for (IconDirectoryEntries::iterator i(m_dirEntries.begin());
     276         i != m_dirEntries.end(); ++i)
     277        *i = readDirectoryEntry();  // Updates m_decodedOffset.
     278
     279    // Make sure the specified image offsets are past the end of the directory
     280    // entries.
     281    for (IconDirectoryEntries::iterator i(m_dirEntries.begin());
     282         i != m_dirEntries.end(); ++i) {
     283        if (i->m_imageOffset < m_decodedOffset) {
     284            setFailed();
     285            return false;
     286        }
     287    }
     288
     289    // Arrange frames in decreasing quality order.
     290    std::sort(m_dirEntries.begin(), m_dirEntries.end(), compareEntries);
     291
     292    // The image size is the size of the largest entry.
     293    const IconDirectoryEntry& dirEntry = m_dirEntries.first();
     294    setSize(dirEntry.m_size.width(), dirEntry.m_size.height());
    215295    return true;
    216296}
     
    219299{
    220300    // Read icon data.
     301    // The casts to uint8_t in the next few lines are because that's the on-disk
     302    // type of the width and height values.  Storing them in ints (instead of
     303    // matching uint8_ts) is so we can record dimensions of size 256 (which is
     304    // what a zero byte really means).
     305    int width = static_cast<uint8_t>(m_data->data()[m_decodedOffset]);
     306    if (width == 0)
     307        width = 256;
     308    int height = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]);
     309    if (height == 0)
     310        height = 256;
    221311    IconDirectoryEntry entry;
    222     entry.bWidth = static_cast<uint8_t>(m_data->data()[m_decodedOffset]);
    223     if (entry.bWidth == 0)
    224         entry.bWidth = 256;
    225     entry.bHeight = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]);
    226     if (entry.bHeight == 0)
    227         entry.bHeight = 256;
    228     entry.wBitCount = readUint16(6);
    229     entry.dwImageOffset = readUint32(12);
     312    entry.m_size = IntSize(width, height);
     313    entry.m_bitCount = readUint16(6);
     314    entry.m_imageOffset = readUint32(12);
    230315
    231316    // Some icons don't have a bit depth, only a color count.  Convert the
     
    233318    // this isn't quite what the bitmap info header says later, as we only use
    234319    // this value to determine which icon entry is best.
    235     if (!entry.wBitCount) {
     320    if (!entry.m_bitCount) {
    236321        uint8_t colorCount = m_data->data()[m_decodedOffset + 2];
    237322        if (colorCount) {
    238323            for (--colorCount; colorCount; colorCount >>= 1)
    239                 ++entry.wBitCount;
     324                ++entry.m_bitCount;
    240325        }
    241326    }
     
    245330}
    246331
    247 bool ICOImageDecoder::isBetterEntry(const IconDirectoryEntry& entry) const
    248 {
    249     const IntSize entrySize(entry.bWidth, entry.bHeight);
    250     const IntSize dirEntrySize(m_dirEntry.bWidth, m_dirEntry.bHeight);
    251     const int entryArea = entry.bWidth * entry.bHeight;
    252     const int dirEntryArea = m_dirEntry.bWidth * m_dirEntry.bHeight;
    253 
    254     if ((entrySize != dirEntrySize) && !m_preferredIconSize.isEmpty()) {
    255         // An icon of exactly the preferred size is best.
    256         if (entrySize == m_preferredIconSize)
    257             return true;
    258         if (dirEntrySize == m_preferredIconSize)
    259             return false;
    260 
    261         // The icon closest to the preferred area without being smaller is
    262         // better.
    263         if (entryArea != dirEntryArea) {
    264             return (entryArea < dirEntryArea) && (entryArea >=
    265                 (m_preferredIconSize.width() * m_preferredIconSize.height()));
    266         }
    267     }
    268 
    269     // Larger icons are better.
    270     if (entryArea != dirEntryArea)
    271         return (entryArea > dirEntryArea);
    272 
    273     // Higher bit-depth icons are better.
    274     return (entry.wBitCount > m_dirEntry.wBitCount);
    275 }
    276 
    277 bool ICOImageDecoder::processImageType()
     332ICOImageDecoder::ImageType ICOImageDecoder::imageTypeAtIndex(size_t index)
    278333{
    279334    // Check if this entry is a BMP or a PNG; we need 4 bytes to check the magic
    280335    // number.
    281     ASSERT(m_decodedOffset == m_dirEntry.dwImageOffset);
    282     if ((m_decodedOffset > m_data->size())
    283         || ((m_data->size() - m_decodedOffset) < 4))
    284         return false;
    285     m_imageType =
    286         strncmp(&m_data->data()[m_decodedOffset], "\x89PNG", 4) ? BMP : PNG;
    287     return true;
    288 }
    289 
    290 }
     336    ASSERT(index < m_dirEntries.size());
     337    const uint32_t imageOffset = m_dirEntries[index].m_imageOffset;
     338    if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4))
     339        return Unknown;
     340    return strncmp(&m_data->data()[imageOffset], "\x89PNG", 4) ? BMP : PNG;
     341}
     342
     343}
  • trunk/WebCore/platform/image-decoders/ico/ICOImageDecoder.h

    r44874 r46807  
    4141    class ICOImageDecoder : public ImageDecoder {
    4242    public:
    43         // See comments on |m_preferredIconSize| below.
    44         ICOImageDecoder(const IntSize& preferredIconSize);
     43        ICOImageDecoder();
     44        virtual ~ICOImageDecoder();
    4545
    4646        // ImageDecoder
     
    4949        virtual bool isSizeAvailable();
    5050        virtual IntSize size() const;
    51         virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
     51        virtual IntSize frameSizeAtIndex(size_t) const;
     52        virtual bool setSize(unsigned width, unsigned height);
     53        virtual size_t frameCount();
     54        virtual RGBA32Buffer* frameBufferAtIndex(size_t);
    5255
    5356    private:
     
    5861        };
    5962
    60         // These are based on the Windows ICONDIR and ICONDIRENTRY structs, but
    61         // with unnecessary entries removed.
    62         struct IconDirectory {
    63             uint16_t idCount;
     63        struct IconDirectoryEntry {
     64            IntSize m_size;
     65            uint16_t m_bitCount;
     66            uint32_t m_imageOffset;
    6467        };
    65         struct IconDirectoryEntry {
    66             uint16_t bWidth;   // 16 bits so we can represent 256 as 256, not 0
    67             uint16_t bHeight;  // "
    68             uint16_t wBitCount;
    69             uint32_t dwImageOffset;
    70         };
     68
     69        // Returns true if |a| is a preferable icon entry to |b|.
     70        // Larger sizes, or greater bitdepths at the same size, are preferable.
     71        static bool compareEntries(const IconDirectoryEntry& a,
     72                                   const IconDirectoryEntry& b);
    7173
    7274        inline uint16_t readUint16(int offset) const
     
    8284        }
    8385
    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.
     86        // If the desired PNGImageDecoder exists, gives it the appropriate data.
     87        void setDataForPNGDecoderAtIndex(size_t);
     88
     89        // Decodes the entry at |index|.  If |onlySize| is true, stops decoding
     90        // after calculating the image size.  If decoding fails but there is no
     91        // more data coming, sets the "decode failure" flag.
    8792        //
    8893        // NOTE: If the desired entry is a PNG, this doesn't actually trigger
     
    9095        // decode.  The caller will then call a function on the PNGImageDecoder
    9196        // that actually triggers decoding.
    92         void decodeWithCheckForDataEnded(bool onlySize);
     97        void decodeWithCheckForDataEnded(size_t index, bool onlySize);
    9398
    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);
     99        // Decodes the directory and directory entries at the beginning of the
     100        // data, and initializes members.  Returns true if all decoding
     101        // succeeded.  Once this returns true, all entries' sizes are known.
     102        bool decodeDirectory();
     103
     104        // Decodes the specified entry.
     105        bool decodeAtIndex(size_t);
    99106
    100107        // Processes the ICONDIR at the beginning of the data.  Returns true if
     
    111118        IconDirectoryEntry readDirectoryEntry();
    112119
    113         // Returns true if |entry| is a preferable icon entry to m_dirEntry.
    114         // Larger sizes, or greater bitdepths at the same size, are preferable.
    115         bool isBetterEntry(const IconDirectoryEntry&) const;
    116 
    117120        // Determines whether the desired entry is a BMP or PNG.  Returns true
    118121        // if the type could be determined.
    119         bool processImageType();
     122        ImageType imageTypeAtIndex(size_t);
    120123
    121124        // True if we've seen all the data.
     
    127130        size_t m_decodedOffset;
    128131
    129         // The entry size we should prefer.  If this is empty, we choose the
    130         // largest available size.  If no entries of the desired size are
    131         // available, we pick the next larger size.
    132         IntSize m_preferredIconSize;
     132        // The headers for the ICO.
     133        typedef Vector<IconDirectoryEntry> IconDirectoryEntries;
     134        IconDirectoryEntries m_dirEntries;
    133135
    134         // The headers for the ICO.
    135         IconDirectory m_directory;
    136         IconDirectoryEntry m_dirEntry;
     136        // The image decoders for the various frames.
     137        typedef Vector<BMPImageReader*> BMPReaders;
     138        BMPReaders m_bmpReaders;
     139        typedef Vector<PNGImageDecoder*> PNGDecoders;
     140        PNGDecoders m_pngDecoders;
    137141
    138         // The BMP reader, if we need to use one.
    139         OwnPtr<BMPImageReader> m_bmpReader;
    140 
    141         // The PNG decoder, if we need to use one.
    142         OwnPtr<PNGImageDecoder> m_pngDecoder;
    143 
    144         // What kind of image data is stored at the entry we're decoding.
    145         ImageType m_imageType;
     142        // Valid only while a BMPImageReader is decoding, this holds the size
     143        // for the particular entry being decoded.
     144        IntSize m_frameSize;
    146145    };
    147146
Note: See TracChangeset for help on using the changeset viewer.