Update WebKit Build Archives page on webkit.org
[WebKit-https.git] / Source / WebCore / platform / image-decoders / webp / WEBPImageDecoder.cpp
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 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 #include <wtf/UniqueArray.h>
32
33 #if USE(WEBP)
34
35 namespace WebCore {
36
37 // Convenience function to improve code readability, as WebPDemuxGetFrame is +1 based.
38 bool webpFrameAtIndex(WebPDemuxer* demuxer, size_t index, WebPIterator* webpFrame)
39 {
40     return WebPDemuxGetFrame(demuxer, index + 1, webpFrame);
41 }
42
43 WEBPImageDecoder::WEBPImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
44     : ScalableImageDecoder(alphaOption, gammaAndColorProfileOption)
45 {
46 }
47
48 WEBPImageDecoder::~WEBPImageDecoder() = default;
49
50 void WEBPImageDecoder::setData(SharedBuffer& data, bool allDataReceived)
51 {
52     if (failed())
53         return;
54
55     // We need to ensure that the header is parsed everytime new data arrives, as the number
56     // of frames may change until we have the complete data. If the size has not been obtained
57     // yet, the call to ScalableImageDecoder::setData() will call parseHeader() and set
58     // m_headerParsed to true, so the call to parseHeader() at the end won't do anything. If the size
59     // is available, then parseHeader() is only called once.
60     m_headerParsed = false;
61     ScalableImageDecoder::setData(data, allDataReceived);
62     parseHeader();
63 }
64
65 RepetitionCount WEBPImageDecoder::repetitionCount() const
66 {
67     if (failed())
68         return RepetitionCountOnce;
69
70     return m_repetitionCount ? m_repetitionCount : RepetitionCountInfinite;
71 }
72
73 ScalableImageDecoderFrame* WEBPImageDecoder::frameBufferAtIndex(size_t index)
74 {
75     if (index >= frameCount())
76         return 0;
77
78     // The size of m_frameBufferCache may be smaller than the index requested. This can happen
79     // because new data may have arrived with a bigger frameCount, but decode() hasn't been called
80     // yet, which is the one that resizes the cache.
81     if ((m_frameBufferCache.size() > index) && m_frameBufferCache[index].isComplete())
82         return &m_frameBufferCache[index];
83
84     decode(index, isAllDataReceived());
85
86     return &m_frameBufferCache[index];
87 }
88
89 size_t WEBPImageDecoder::findFirstRequiredFrameToDecode(size_t frameIndex, WebPDemuxer* demuxer)
90 {
91     // The first frame doesn't depend on any other.
92     if (!frameIndex)
93         return 0;
94
95     // Go backwards and find the first complete frame.
96     size_t firstIncompleteFrame = frameIndex;
97     for (; firstIncompleteFrame; --firstIncompleteFrame) {
98         if (m_frameBufferCache[firstIncompleteFrame - 1].isComplete())
99             break;
100     }
101
102     // Check if there are any independent frames between firstIncompleteFrame and frameIndex.
103     for (size_t firstIndependentFrame = frameIndex; firstIndependentFrame > firstIncompleteFrame ; --firstIndependentFrame) {
104         WebPIterator webpFrame;
105         if (!webpFrameAtIndex(demuxer, firstIndependentFrame, &webpFrame))
106             continue;
107
108         IntRect frameRect(webpFrame.x_offset, webpFrame.y_offset, webpFrame.width, webpFrame.height);
109         if (!frameRect.contains({ { }, size() }))
110             continue;
111
112         // This frame covers the whole area and doesn't have alpha, so it can be rendered without
113         // dependencies.
114         if (!webpFrame.has_alpha)
115             return firstIndependentFrame;
116
117         // This frame covers the whole area and its disposalMethod is RestoreToBackground, which means
118         // that the next frame will be rendered on top of a transparent background, and can be decoded
119         // without dependencies. This can only be checked for frames prior to frameIndex.
120         if (firstIndependentFrame < frameIndex && m_frameBufferCache[firstIndependentFrame].disposalMethod() == ScalableImageDecoderFrame::DisposalMethod::RestoreToBackground)
121             return firstIndependentFrame + 1;
122     }
123
124     return firstIncompleteFrame;
125 }
126
127 void WEBPImageDecoder::decode(size_t frameIndex, bool allDataReceived)
128 {
129     if (failed())
130         return;
131
132     // This can be executed both in the main thread (when not using async decoding) or in the decoding thread.
133     // When executed in the decoding thread, a call to setData() from the main thread may change the data
134     // the WebPDemuxer is using, leaving it in an inconsistent state, so we need to protect the data.
135     RefPtr<SharedBuffer> protectedData(m_data);
136     WebPData inputData = { reinterpret_cast<const uint8_t*>(protectedData->data()), protectedData->size() };
137     WebPDemuxState demuxerState;
138     WebPDemuxer* demuxer = WebPDemuxPartial(&inputData, &demuxerState);
139     if (!demuxer) {
140         setFailed();
141         return;
142     }
143
144     m_frameBufferCache.resize(m_frameCount);
145
146     // It is a fatal error if all data is received and we have decoded all frames available but the file is truncated.
147     if (frameIndex >= m_frameBufferCache.size() - 1 && allDataReceived && demuxer && demuxerState != WEBP_DEMUX_DONE) {
148         WebPDemuxDelete(demuxer);
149         setFailed();
150         return;
151     }
152
153     for (size_t i = findFirstRequiredFrameToDecode(frameIndex, demuxer); i <= frameIndex; i++)
154         decodeFrame(i, demuxer);
155
156     WebPDemuxDelete(demuxer);
157 }
158
159 void WEBPImageDecoder::decodeFrame(size_t frameIndex, WebPDemuxer* demuxer)
160 {
161     if (failed())
162         return;
163
164     WebPIterator webpFrame;
165     if (!webpFrameAtIndex(demuxer, frameIndex, &webpFrame))
166         return;
167
168     const uint8_t* dataBytes = reinterpret_cast<const uint8_t*>(webpFrame.fragment.bytes);
169     size_t dataSize = webpFrame.fragment.size;
170     bool blend = webpFrame.blend_method == WEBP_MUX_BLEND ? true : false;
171
172     ASSERT(m_frameBufferCache.size() > frameIndex);
173     auto& buffer = m_frameBufferCache[frameIndex];
174     buffer.setDuration(Seconds::fromMilliseconds(webpFrame.duration));
175     buffer.setDisposalMethod(webpFrame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? ScalableImageDecoderFrame::DisposalMethod::RestoreToBackground : ScalableImageDecoderFrame::DisposalMethod::DoNotDispose);
176     ASSERT(!buffer.isComplete());
177
178     if (buffer.isInvalid() && !initFrameBuffer(frameIndex, &webpFrame)) {
179         setFailed();
180         return;
181     }
182
183     WebPDecBuffer decoderBuffer;
184     WebPInitDecBuffer(&decoderBuffer);
185     decoderBuffer.colorspace = MODE_RGBA;
186     decoderBuffer.u.RGBA.stride = webpFrame.width * sizeof(uint32_t);
187     decoderBuffer.u.RGBA.size = decoderBuffer.u.RGBA.stride * webpFrame.height;
188     decoderBuffer.is_external_memory = 1;
189     auto p = makeUniqueArray<uint8_t>(decoderBuffer.u.RGBA.size);
190     decoderBuffer.u.RGBA.rgba = p.get();
191     if (!decoderBuffer.u.RGBA.rgba) {
192         setFailed();
193         return;
194     }
195
196     WebPIDecoder* decoder = WebPINewDecoder(&decoderBuffer);
197     if (!decoder) {
198         setFailed();
199         return;
200     }
201
202     switch (WebPIUpdate(decoder, dataBytes, dataSize)) {
203     case VP8_STATUS_OK:
204         applyPostProcessing(frameIndex, decoder, decoderBuffer, blend);
205         buffer.setDecodingStatus(DecodingStatus::Complete);
206         break;
207     case VP8_STATUS_SUSPENDED:
208         if (!isAllDataReceived()) {
209             applyPostProcessing(frameIndex, decoder, decoderBuffer, blend);
210             buffer.setDecodingStatus(DecodingStatus::Partial);
211             break;
212         }
213         // Fallthrough.
214     default:
215         setFailed();
216     }
217
218     WebPIDelete(decoder);
219 }
220
221 bool WEBPImageDecoder::initFrameBuffer(size_t frameIndex, const WebPIterator* webpFrame)
222 {
223     if (frameIndex >= frameCount())
224         return false;
225
226     auto& buffer = m_frameBufferCache[frameIndex];
227
228     // Initialize the frame rect in our buffer.
229     IntRect frameRect(webpFrame->x_offset, webpFrame->y_offset, webpFrame->width, webpFrame->height);
230
231     // Make sure the frameRect doesn't extend outside the buffer.
232     frameRect.intersect({ { }, size() });
233
234     if (!frameIndex || !m_frameBufferCache[frameIndex - 1].backingStore()) {
235         // This frame doesn't rely on any previous data.
236         if (!buffer.initialize(size(), m_premultiplyAlpha))
237             return false;
238     } else {
239         const auto& prevBuffer = m_frameBufferCache[frameIndex - 1];
240         ASSERT(prevBuffer.isComplete());
241
242         // Preserve the last frame as the starting state for this frame.
243         if (!prevBuffer.backingStore() || !buffer.initialize(*prevBuffer.backingStore()))
244             return false;
245
246         if (prevBuffer.disposalMethod() == ScalableImageDecoderFrame::DisposalMethod::RestoreToBackground) {
247             // We want to clear the previous frame to transparent, without
248             // affecting pixels in the image outside of the frame.
249             const IntRect& prevRect = prevBuffer.backingStore()->frameRect();
250             buffer.backingStore()->clearRect(prevRect);
251         }
252     }
253
254     buffer.setHasAlpha(webpFrame->has_alpha);
255     buffer.backingStore()->setFrameRect(frameRect);
256
257     return true;
258 }
259
260 void WEBPImageDecoder::applyPostProcessing(size_t frameIndex, WebPIDecoder* decoder, WebPDecBuffer& decoderBuffer, bool blend)
261 {
262     auto& buffer = m_frameBufferCache[frameIndex];
263     int decodedWidth = 0;
264     int decodedHeight = 0;
265     if (!WebPIDecGetRGB(decoder, &decodedHeight, &decodedWidth, 0, 0))
266         return; // See also https://bugs.webkit.org/show_bug.cgi?id=74062
267     if (decodedHeight <= 0)
268         return;
269
270     const IntRect& frameRect = buffer.backingStore()->frameRect();
271     ASSERT_WITH_SECURITY_IMPLICATION(decodedWidth == frameRect.width());
272     ASSERT_WITH_SECURITY_IMPLICATION(decodedHeight <= frameRect.height());
273     const int left = frameRect.x();
274     const int top = frameRect.y();
275
276     for (int y = 0; y < decodedHeight; y++) {
277         const int canvasY = top + y;
278         for (int x = 0; x < decodedWidth; x++) {
279             const int canvasX = left + x;
280             auto* address = buffer.backingStore()->pixelAt(canvasX, canvasY);
281             uint8_t* pixel = decoderBuffer.u.RGBA.rgba + (y * frameRect.width() + x) * sizeof(uint32_t);
282             if (blend && (pixel[3] < 255))
283                 buffer.backingStore()->blendPixel(address, pixel[0], pixel[1], pixel[2], pixel[3]);
284             else
285                 buffer.backingStore()->setPixel(address, pixel[0], pixel[1], pixel[2], pixel[3]);
286         }
287     }
288 }
289
290 void WEBPImageDecoder::parseHeader()
291 {
292     if (m_headerParsed)
293         return;
294
295     m_headerParsed = true;
296
297     const unsigned webpHeaderSize = 30; // RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8_FRAME_HEADER_SIZE
298     if (m_data->size() < webpHeaderSize)
299         return; // Await VP8X header so WebPDemuxPartial succeeds.
300
301     WebPData inputData = { reinterpret_cast<const uint8_t*>(m_data->data()), m_data->size() };
302     WebPDemuxState demuxerState;
303     WebPDemuxer* demuxer = WebPDemuxPartial(&inputData, &demuxerState);
304     if (!demuxer) {
305         setFailed();
306         return;
307     }
308
309     m_frameCount = WebPDemuxGetI(demuxer, WEBP_FF_FRAME_COUNT);
310     if (!m_frameCount) {
311         WebPDemuxDelete(demuxer);
312         return; // Wait until the encoded image frame data arrives.
313     }
314
315     int width = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH);
316     int height = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT);
317     if (!isSizeAvailable() && !setSize(IntSize(width, height))) {
318         WebPDemuxDelete(demuxer);
319         return;
320     }
321
322     m_formatFlags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS);
323     if (!(m_formatFlags & ANIMATION_FLAG))
324         m_repetitionCount = WebCore::RepetitionCountNone;
325     else {
326         // Since we have parsed at least one frame, even if partially,
327         // the global animation (ANIM) properties have been read since
328         // an ANIM chunk must precede the ANMF frame chunks.
329         m_repetitionCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT);
330         ASSERT(m_repetitionCount == (m_repetitionCount & 0xffff)); // Loop count is always <= 16 bits.
331         if (!m_repetitionCount)
332             m_repetitionCount = WebCore::RepetitionCountInfinite;
333     }
334
335     WebPDemuxDelete(demuxer);
336 }
337
338 void WEBPImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
339 {
340     if (m_frameBufferCache.isEmpty())
341         return;
342
343     // We don't want to delete the last frame in the cache, as is may be needed for
344     // decoding when new data arrives. See GIFImageDecoder for the full explanation.
345     clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1);
346
347     // Also from GIFImageDecoder: We need to preserve frames such that:
348     //   * We don't clear |clearBeforeFrame|.
349     //   * We don't clear the frame we're currently decoding.
350     //   * We don't clear any frame from which a future initFrameBuffer() call will copy bitmap data.
351     //
352     // In WEBP every frame depends on the previous one or none. That means that frames after clearBeforeFrame
353     // won't need any frame before them to render, so we can clear them all.
354     for (int i = clearBeforeFrame - 1; i >= 0; i--) {
355         auto& buffer = m_frameBufferCache[i];
356         if (!buffer.isInvalid())
357             buffer.clear();
358     }
359 }
360
361 } // namespace WebCore
362
363 #endif