1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "WEBPImageDecoder.h" 31 32#if USE(WEBP) 33 34#include "webp/decode.h" 35 36namespace WebCore { 37 38WEBPImageDecoder::WEBPImageDecoder(ImageSource::AlphaOption alphaOption, 39 ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) 40 : ImageDecoder(alphaOption, gammaAndColorProfileOption) 41 , m_decoder(0) 42 , m_lastVisibleRow(0) 43{ 44} 45 46WEBPImageDecoder::~WEBPImageDecoder() 47{ 48} 49 50bool WEBPImageDecoder::isSizeAvailable() 51{ 52 if (!ImageDecoder::isSizeAvailable()) 53 decode(true); 54 55 return ImageDecoder::isSizeAvailable(); 56} 57 58ImageFrame* WEBPImageDecoder::frameBufferAtIndex(size_t index) 59{ 60 if (index) 61 return 0; 62 63 if (m_frameBufferCache.isEmpty()) { 64 m_frameBufferCache.resize(1); 65 m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); 66 } 67 68 ImageFrame& frame = m_frameBufferCache[0]; 69 if (frame.status() != ImageFrame::FrameComplete) 70 decode(false); 71 return &frame; 72} 73 74 75bool WEBPImageDecoder::decode(bool onlySize) 76{ 77 // Minimum number of bytes needed to ensure one can parse size information. 78 static const size_t sizeOfHeader = 30; 79 // Number of bytes per pixel. 80 static const int bytesPerPixel = 3; 81 82 if (failed()) 83 return false; 84 85 const size_t dataSize = m_data->size(); 86 if (dataSize < sizeOfHeader) 87 return true; 88 89 int width, height; 90 const uint8_t* dataBytes = reinterpret_cast<const uint8_t*>(m_data->data()); 91 if (!WebPGetInfo(dataBytes, dataSize, &width, &height)) 92 return setFailed(); 93 if (!ImageDecoder::isSizeAvailable() && !setSize(width, height)) 94 return setFailed(); 95 if (onlySize) 96 return true; 97 98 bool allDataReceived = isAllDataReceived(); 99 int stride = width * bytesPerPixel; 100 ASSERT(!m_frameBufferCache.isEmpty()); 101 ImageFrame& buffer = m_frameBufferCache[0]; 102 if (buffer.status() == ImageFrame::FrameEmpty) { 103 ASSERT(width == size().width()); 104 ASSERT(height == size().height()); 105 if (!buffer.setSize(width, height)) 106 return setFailed(); 107 buffer.setStatus(allDataReceived ? ImageFrame::FrameComplete : ImageFrame::FramePartial); 108 // FIXME: We currently hard code false below because libwebp doesn't support alpha yet. 109 buffer.setHasAlpha(false); 110 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); 111 m_rgbOutput.resize(height * stride); 112 } 113 int newLastVisibleRow = 0; // Last completed row. 114 if (allDataReceived) { 115 if (!WebPDecodeRGBInto(dataBytes, dataSize, m_rgbOutput.data(), m_rgbOutput.size(), stride)) 116 return setFailed(); 117 newLastVisibleRow = height; 118 } else { 119 if (!m_decoder) { 120 m_decoder = WebPINewRGB(MODE_RGB, m_rgbOutput.data(), m_rgbOutput.size(), stride); 121 if (!m_decoder) 122 return setFailed(); 123 } 124 const VP8StatusCode status = WebPIUpdate(m_decoder, dataBytes, dataSize); 125 if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) 126 return setFailed(); 127 if (!WebPIDecGetRGB(m_decoder, &newLastVisibleRow, 0, 0, 0)) 128 return setFailed(); 129 ASSERT(newLastVisibleRow >= 0); 130 ASSERT(newLastVisibleRow <= height); 131 } 132 // FIXME: remove this data copy. 133 for (int y = m_lastVisibleRow; y < newLastVisibleRow; ++y) { 134 const uint8_t* const src = &m_rgbOutput[y * stride]; 135 for (int x = 0; x < width; ++x) 136 buffer.setRGBA(x, y, src[bytesPerPixel * x + 0], src[bytesPerPixel * x + 1], src[bytesPerPixel * x + 2], 0xff); 137 } 138 m_lastVisibleRow = newLastVisibleRow; 139 if (m_lastVisibleRow == height) 140 buffer.setStatus(ImageFrame::FrameComplete); 141 return m_lastVisibleRow == height; 142} 143 144} 145 146#endif 147