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