Commit 0bad3920 authored by scroggo@chromium.org's avatar scroggo@chromium.org

Never consolidate data in ICO decoder

Follows the same approach as BMPImageDecoder: Use a
FastSharedBufferReader to avoid consolidation.

Add an optional offset to PNGImageDecoder for ICOImageDecoder, so that
PNGImageDecoder can read a PNG subimage in an ICO without copying the
data. This eliminates another call to SharedBuffer::data(), as well as
a copy to create the separate SharedBuffer for PNG.

BUG=467772
BUG=528625

Review URL: https://codereview.chromium.org/1316203008

git-svn-id: svn://svn.chromium.org/blink/trunk@201981 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 9ceab7f6
...@@ -46,6 +46,7 @@ static const size_t sizeOfDirEntry = 16; ...@@ -46,6 +46,7 @@ static const size_t sizeOfDirEntry = 16;
ICOImageDecoder::ICOImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption colorOptions, size_t maxDecodedBytes) ICOImageDecoder::ICOImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption colorOptions, size_t maxDecodedBytes)
: ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes)
, m_fastReader(nullptr)
, m_decodedOffset(0) , m_decodedOffset(0)
{ {
} }
...@@ -56,6 +57,8 @@ ICOImageDecoder::~ICOImageDecoder() ...@@ -56,6 +57,8 @@ ICOImageDecoder::~ICOImageDecoder()
void ICOImageDecoder::onSetData(SharedBuffer* data) void ICOImageDecoder::onSetData(SharedBuffer* data)
{ {
m_fastReader.setData(data);
for (BMPReaders::iterator i(m_bmpReaders.begin()); i != m_bmpReaders.end(); ++i) { for (BMPReaders::iterator i(m_bmpReaders.begin()); i != m_bmpReaders.end(); ++i) {
if (*i) if (*i)
(*i)->setData(data); (*i)->setData(data);
...@@ -126,12 +129,7 @@ void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index) ...@@ -126,12 +129,7 @@ void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index)
if (!m_pngDecoders[index]) if (!m_pngDecoders[index])
return; return;
const IconDirectoryEntry& dirEntry = m_dirEntries[index]; m_pngDecoders[index]->setData(m_data.get(), isAllDataReceived());
// Copy out PNG data to a separate vector and send to the PNG decoder.
// FIXME: Save this copy by making the PNG decoder able to take an
// optional offset.
RefPtr<SharedBuffer> pngData(SharedBuffer::create(&m_data->data()[dirEntry.m_imageOffset], m_data->size() - dirEntry.m_imageOffset));
m_pngDecoders[index]->setData(pngData.get(), isAllDataReceived());
} }
void ICOImageDecoder::decode(size_t index, bool onlySize) void ICOImageDecoder::decode(size_t index, bool onlySize)
...@@ -186,11 +184,12 @@ bool ICOImageDecoder::decodeAtIndex(size_t index) ...@@ -186,11 +184,12 @@ bool ICOImageDecoder::decodeAtIndex(size_t index)
} }
if (!m_pngDecoders[index]) { if (!m_pngDecoders[index]) {
m_pngDecoders[index] = adoptPtr( AlphaOption alphaOption = m_premultiplyAlpha ? AlphaPremultiplied : AlphaNotPremultiplied;
new PNGImageDecoder(m_premultiplyAlpha ? AlphaPremultiplied : AlphaNotPremultiplied, GammaAndColorProfileOption colorOptions = m_ignoreGammaAndColorProfile ? GammaAndColorProfileIgnored : GammaAndColorProfileApplied;
m_ignoreGammaAndColorProfile ? GammaAndColorProfileIgnored : GammaAndColorProfileApplied, m_maxDecodedBytes)); m_pngDecoders[index] = adoptPtr(new PNGImageDecoder(alphaOption, colorOptions, m_maxDecodedBytes, dirEntry.m_imageOffset));
setDataForPNGDecoderAtIndex(index); setDataForPNGDecoderAtIndex(index);
} }
// Fail if the size the PNGImageDecoder calculated does not match the size // Fail if the size the PNGImageDecoder calculated does not match the size
// in the directory. // in the directory.
if (m_pngDecoders[index]->isSizeAvailable() && (m_pngDecoders[index]->size() != dirEntry.m_size)) if (m_pngDecoders[index]->isSizeAvailable() && (m_pngDecoders[index]->size() != dirEntry.m_size))
...@@ -253,14 +252,14 @@ bool ICOImageDecoder::processDirectoryEntries() ...@@ -253,14 +252,14 @@ bool ICOImageDecoder::processDirectoryEntries()
ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry()
{ {
// Read icon data. // Read icon data.
// The casts to uint8_t in the next few lines are because that's the on-disk // The following calls to readUint8() return a uint8_t, which is appropriate
// type of the width and height values. Storing them in ints (instead of // because that's the on-disk type of the width and height values. Storing
// matching uint8_ts) is so we can record dimensions of size 256 (which is // them in ints (instead of matching uint8_ts) is so we can record dimensions
// what a zero byte really means). // of size 256 (which is what a zero byte really means).
int width = static_cast<uint8_t>(m_data->data()[m_decodedOffset]); int width = readUint8(0);
if (!width) if (!width)
width = 256; width = 256;
int height = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]); int height = readUint8(1);
if (!height) if (!height)
height = 256; height = 256;
IconDirectoryEntry entry; IconDirectoryEntry entry;
...@@ -279,7 +278,7 @@ ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() ...@@ -279,7 +278,7 @@ ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry()
// this isn't quite what the bitmap info header says later, as we only use // this isn't quite what the bitmap info header says later, as we only use
// this value to determine which icon entry is best. // this value to determine which icon entry is best.
if (!entry.m_bitCount) { if (!entry.m_bitCount) {
int colorCount = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 2]); int colorCount = readUint8(2);
if (!colorCount) if (!colorCount)
colorCount = 256; // Vague in the spec, needed by real-world icons. colorCount = 256; // Vague in the spec, needed by real-world icons.
for (--colorCount; colorCount; colorCount >>= 1) for (--colorCount; colorCount; colorCount >>= 1)
...@@ -298,7 +297,9 @@ ICOImageDecoder::ImageType ICOImageDecoder::imageTypeAtIndex(size_t index) ...@@ -298,7 +297,9 @@ ICOImageDecoder::ImageType ICOImageDecoder::imageTypeAtIndex(size_t index)
const uint32_t imageOffset = m_dirEntries[index].m_imageOffset; const uint32_t imageOffset = m_dirEntries[index].m_imageOffset;
if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4)) if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4))
return Unknown; return Unknown;
return strncmp(&m_data->data()[imageOffset], "\x89PNG", 4) ? BMP : PNG; char buffer[4];
const char* data = m_fastReader.getConsecutiveData(imageOffset, 4, buffer);
return strncmp(data, "\x89PNG", 4) ? BMP : PNG;
} }
} }
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifndef ICOImageDecoder_h #ifndef ICOImageDecoder_h
#define ICOImageDecoder_h #define ICOImageDecoder_h
#include "platform/image-decoders/FastSharedBufferReader.h"
#include "platform/image-decoders/bmp/BMPImageReader.h" #include "platform/image-decoders/bmp/BMPImageReader.h"
namespace blink { namespace blink {
...@@ -83,16 +84,24 @@ private: ...@@ -83,16 +84,24 @@ private:
size_t decodeFrameCount() override; size_t decodeFrameCount() override;
void decode(size_t index) override { decode(index, false); } void decode(size_t index) override { decode(index, false); }
// TODO (scroggo): These functions are identical to functions in BMPImageReader. Share code?
inline uint8_t readUint8(size_t offset) const
{
return m_fastReader.getOneByte(m_decodedOffset + offset);
}
inline uint16_t readUint16(int offset) const inline uint16_t readUint16(int offset) const
{ {
// TODO (scroggo): This consolidates the data, meaning unnecessary copies. char buffer[2];
return BMPImageReader::readUint16(&m_data->data()[m_decodedOffset + offset]); const char* data = m_fastReader.getConsecutiveData(m_decodedOffset + offset, 2, buffer);
return BMPImageReader::readUint16(data);
} }
inline uint32_t readUint32(int offset) const inline uint32_t readUint32(int offset) const
{ {
// TODO (scroggo): This consolidates the data, meaning unnecessary copies. char buffer[4];
return BMPImageReader::readUint32(&m_data->data()[m_decodedOffset + offset]); const char* data = m_fastReader.getConsecutiveData(m_decodedOffset + offset, 4, buffer);
return BMPImageReader::readUint32(data);
} }
// If the desired PNGImageDecoder exists, gives it the appropriate data. // If the desired PNGImageDecoder exists, gives it the appropriate data.
...@@ -132,6 +141,8 @@ private: ...@@ -132,6 +141,8 @@ private:
// if the type could be determined. // if the type could be determined.
ImageType imageTypeAtIndex(size_t); ImageType imageTypeAtIndex(size_t);
FastSharedBufferReader m_fastReader;
// An index into |m_data| representing how much we've already decoded. // An index into |m_data| representing how much we've already decoded.
// Note that this only tracks data _this_ class decodes; once the // Note that this only tracks data _this_ class decodes; once the
// BMPImageReader takes over this will not be updated further. // BMPImageReader takes over this will not be updated further.
......
...@@ -89,9 +89,9 @@ namespace blink { ...@@ -89,9 +89,9 @@ namespace blink {
class PNGImageReader { class PNGImageReader {
WTF_MAKE_FAST_ALLOCATED(PNGImageReader); WTF_MAKE_FAST_ALLOCATED(PNGImageReader);
public: public:
PNGImageReader(PNGImageDecoder* decoder) PNGImageReader(PNGImageDecoder* decoder, unsigned readOffset)
: m_decoder(decoder) : m_decoder(decoder)
, m_readOffset(0) , m_readOffset(readOffset)
, m_currentBufferSize(0) , m_currentBufferSize(0)
, m_decodingSizeOnly(false) , m_decodingSizeOnly(false)
, m_hasAlpha(false) , m_hasAlpha(false)
...@@ -204,9 +204,10 @@ private: ...@@ -204,9 +204,10 @@ private:
#endif #endif
}; };
PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption colorOptions, size_t maxDecodedBytes) PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption colorOptions, size_t maxDecodedBytes, unsigned offset)
: ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes)
, m_hasColorProfile(false) , m_hasColorProfile(false)
, m_offset(offset)
{ {
} }
...@@ -495,7 +496,7 @@ void PNGImageDecoder::decode(bool onlySize) ...@@ -495,7 +496,7 @@ void PNGImageDecoder::decode(bool onlySize)
return; return;
if (!m_reader) if (!m_reader)
m_reader = adoptPtr(new PNGImageReader(this)); m_reader = adoptPtr(new PNGImageReader(this, m_offset));
// If we couldn't decode the image but have received all the data, decoding // If we couldn't decode the image but have received all the data, decoding
// has failed. // has failed.
......
...@@ -37,7 +37,7 @@ class PNGImageReader; ...@@ -37,7 +37,7 @@ class PNGImageReader;
class PLATFORM_EXPORT PNGImageDecoder : public ImageDecoder { class PLATFORM_EXPORT PNGImageDecoder : public ImageDecoder {
WTF_MAKE_NONCOPYABLE(PNGImageDecoder); WTF_MAKE_NONCOPYABLE(PNGImageDecoder);
public: public:
PNGImageDecoder(AlphaOption, GammaAndColorProfileOption, size_t maxDecodedBytes); PNGImageDecoder(AlphaOption, GammaAndColorProfileOption, size_t maxDecodedBytes, unsigned offset = 0);
~PNGImageDecoder() override; ~PNGImageDecoder() override;
// ImageDecoder: // ImageDecoder:
...@@ -61,6 +61,7 @@ private: ...@@ -61,6 +61,7 @@ private:
OwnPtr<PNGImageReader> m_reader; OwnPtr<PNGImageReader> m_reader;
bool m_hasColorProfile; bool m_hasColorProfile;
const unsigned m_offset;
}; };
} // namespace blink } // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment