WEBPImageDecoder.cpp [plain text]
#include "config.h"
#include "WEBPImageDecoder.h"
#if USE(WEBP)
#if (WEBP_DECODER_ABI_VERSION < 0x0163)
#define MODE_rgbA MODE_RGBA
#define MODE_bgrA MODE_BGRA
#endif
#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
inline WEBP_CSP_MODE outputMode(bool hasAlpha) { return hasAlpha ? MODE_rgbA : MODE_RGBA; }
#else // LITTLE_ENDIAN, output BGRA pixels.
inline WEBP_CSP_MODE outputMode(bool hasAlpha) { return hasAlpha ? MODE_bgrA : MODE_BGRA; }
#endif
namespace WebCore {
WEBPImageDecoder::WEBPImageDecoder(ImageSource::AlphaOption alphaOption,
ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
: ImageDecoder(alphaOption, gammaAndColorProfileOption)
, m_decoder(0)
, m_hasAlpha(false)
{
}
WEBPImageDecoder::~WEBPImageDecoder()
{
clear();
}
void WEBPImageDecoder::clear()
{
if (m_decoder)
WebPIDelete(m_decoder);
m_decoder = 0;
}
bool WEBPImageDecoder::isSizeAvailable()
{
if (!ImageDecoder::isSizeAvailable())
decode(true);
return ImageDecoder::isSizeAvailable();
}
ImageFrame* WEBPImageDecoder::frameBufferAtIndex(size_t index)
{
if (index)
return 0;
if (m_frameBufferCache.isEmpty()) {
m_frameBufferCache.resize(1);
m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha);
}
ImageFrame& frame = m_frameBufferCache[0];
if (frame.status() != ImageFrame::FrameComplete)
decode(false);
return &frame;
}
bool WEBPImageDecoder::decode(bool onlySize)
{
if (failed())
return false;
const uint8_t* dataBytes = reinterpret_cast<const uint8_t*>(m_data->data());
const size_t dataSize = m_data->size();
if (!ImageDecoder::isSizeAvailable()) {
static const size_t imageHeaderSize = 30;
if (dataSize < imageHeaderSize)
return false;
int width, height;
#if (WEBP_DECODER_ABI_VERSION >= 0x0163)
WebPBitstreamFeatures features;
if (WebPGetFeatures(dataBytes, dataSize, &features) != VP8_STATUS_OK)
return setFailed();
width = features.width;
height = features.height;
m_hasAlpha = features.has_alpha;
#else
if (!WebPGetInfo(dataBytes, dataSize, &width, &height))
return setFailed();
m_hasAlpha = false;
#endif
if (!setSize(width, height))
return setFailed();
}
ASSERT(ImageDecoder::isSizeAvailable());
if (onlySize)
return true;
ASSERT(!m_frameBufferCache.isEmpty());
ImageFrame& buffer = m_frameBufferCache[0];
ASSERT(buffer.status() != ImageFrame::FrameComplete);
if (buffer.status() == ImageFrame::FrameEmpty) {
if (!buffer.setSize(size().width(), size().height()))
return setFailed();
buffer.setStatus(ImageFrame::FramePartial);
buffer.setHasAlpha(m_hasAlpha);
buffer.setOriginalFrameRect(IntRect(IntPoint(), size()));
}
if (!m_decoder) {
WEBP_CSP_MODE mode = outputMode(m_hasAlpha);
if (!m_premultiplyAlpha)
mode = outputMode(false);
int rowStride = size().width() * sizeof(ImageFrame::PixelData);
uint8_t* output = reinterpret_cast<uint8_t*>(buffer.getAddr(0, 0));
int outputSize = size().height() * rowStride;
m_decoder = WebPINewRGB(mode, output, outputSize, rowStride);
if (!m_decoder)
return setFailed();
}
switch (WebPIUpdate(m_decoder, dataBytes, dataSize)) {
case VP8_STATUS_OK:
buffer.setStatus(ImageFrame::FrameComplete);
clear();
return true;
case VP8_STATUS_SUSPENDED:
return false;
default:
clear();
return setFailed();
}
}
}
#endif