74e6604a7a44c2c24ee107158b2ca418811a46cd
[WebKit-https.git] / Source / WebCore / platform / image-decoders / ImageDecoder.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc.  All rights reserved.
3  * Copyright (C) 2008-2009 Torch Mobile, Inc.
4  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "ImageDecoder.h"
25
26 #include "BMPImageDecoder.h"
27 #include "GIFImageDecoder.h"
28 #include "ICOImageDecoder.h"
29 #include "JPEGImageDecoder.h"
30 #include "PNGImageDecoder.h"
31 #include "SharedBuffer.h"
32 #if USE(WEBP)
33 #include "WEBPImageDecoder.h"
34 #endif
35
36 #include <algorithm>
37 #include <cmath>
38
39 using namespace std;
40
41 namespace WebCore {
42
43 namespace {
44
45 unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
46 {
47     unsigned bytesExtracted = 0;
48     const char* moreData;
49     while (unsigned moreDataLength = sharedBuffer.getSomeData(moreData, offset)) {
50         unsigned bytesToCopy = min(bufferLength - bytesExtracted, moreDataLength);
51         memcpy(buffer + bytesExtracted, moreData, bytesToCopy);
52         bytesExtracted += bytesToCopy;
53         if (bytesExtracted == bufferLength)
54             break;
55         offset += bytesToCopy;
56     }
57     return bytesExtracted;
58 }
59
60 bool matchesGIFSignature(char* contents)
61 {
62     return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6);
63 }
64
65 bool matchesPNGSignature(char* contents)
66 {
67     return !memcmp(contents, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8);
68 }
69
70 bool matchesJPEGSignature(char* contents)
71 {
72     return !memcmp(contents, "\xFF\xD8\xFF", 3);
73 }
74
75 #if USE(WEBP)
76 bool matchesWebPSignature(char* contents)
77 {
78     return !memcmp(contents, "RIFF", 4) && !memcmp(contents + 8, "WEBPVP", 6);
79 }
80 #endif
81
82 bool matchesBMPSignature(char* contents)
83 {
84     return !memcmp(contents, "BM", 2);
85 }
86
87 bool matchesICOSignature(char* contents)
88 {
89     return !memcmp(contents, "\x00\x00\x01\x00", 4);
90 }
91
92 bool matchesCURSignature(char* contents)
93 {
94     return !memcmp(contents, "\x00\x00\x02\x00", 4);
95 }
96
97 }
98
99 std::unique_ptr<ImageDecoder> ImageDecoder::create(const SharedBuffer& data, AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
100 {
101     static const unsigned lengthOfLongestSignature = 14; // To wit: "RIFF????WEBPVP"
102     char contents[lengthOfLongestSignature];
103     unsigned length = copyFromSharedBuffer(contents, lengthOfLongestSignature, data, 0);
104     if (length < lengthOfLongestSignature)
105         return nullptr;
106
107     if (matchesGIFSignature(contents))
108         return std::unique_ptr<ImageDecoder> { std::make_unique<GIFImageDecoder>(alphaOption, gammaAndColorProfileOption) };
109
110     if (matchesPNGSignature(contents))
111         return std::unique_ptr<ImageDecoder> { std::make_unique<PNGImageDecoder>(alphaOption, gammaAndColorProfileOption) };
112
113     if (matchesICOSignature(contents) || matchesCURSignature(contents))
114         return std::unique_ptr<ImageDecoder> { std::make_unique<ICOImageDecoder>(alphaOption, gammaAndColorProfileOption) };
115
116     if (matchesJPEGSignature(contents))
117         return std::unique_ptr<ImageDecoder> { std::make_unique<JPEGImageDecoder>(alphaOption, gammaAndColorProfileOption) };
118
119 #if USE(WEBP)
120     if (matchesWebPSignature(contents))
121         return std::unique_ptr<ImageDecoder> { std::make_unique<WEBPImageDecoder>(alphaOption, gammaAndColorProfileOption) };
122 #endif
123
124     if (matchesBMPSignature(contents))
125         return std::unique_ptr<ImageDecoder> { std::make_unique<BMPImageDecoder>(alphaOption, gammaAndColorProfileOption) };
126
127     return nullptr;
128 }
129
130 namespace {
131
132 enum MatchType {
133     Exact,
134     UpperBound,
135     LowerBound
136 };
137
138 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
139 {
140     double inflateRate = 1. / scaleRate;
141     scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
142     for (int scaledIndex = 0; ; ++scaledIndex) {
143         int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
144         if (index >= length)
145             break;
146         scaledValues.append(index);
147     }
148 }
149
150 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
151 {
152     if (scaledValues.isEmpty())
153         return valueToMatch;
154
155     const int* dataStart = scaledValues.data();
156     const int* dataEnd = dataStart + scaledValues.size();
157     const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
158     switch (type) {
159     case Exact:
160         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
161     case LowerBound:
162         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
163     case UpperBound:
164     default:
165         return matched != dataEnd ? matched - dataStart : -1;
166     }
167 }
168
169 }
170
171 bool ImageDecoder::frameIsCompleteAtIndex(size_t index)
172 {
173     ImageFrame* buffer = frameBufferAtIndex(index);
174     return buffer && buffer->isComplete();
175 }
176
177 bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const
178 {
179     if (m_frameBufferCache.size() <= index)
180         return true;
181     if (m_frameBufferCache[index].isComplete())
182         return m_frameBufferCache[index].hasAlpha();
183     return true;
184 }
185
186 unsigned ImageDecoder::frameBytesAtIndex(size_t index) const
187 {
188     if (m_frameBufferCache.size() <= index)
189         return 0;
190     // FIXME: Use the dimension of the requested frame.
191     return (m_size.area() * sizeof(RGBA32)).unsafeGet();
192 }
193
194 float ImageDecoder::frameDurationAtIndex(size_t index)
195 {
196     ImageFrame* buffer = frameBufferAtIndex(index);
197     if (!buffer || buffer->isEmpty())
198         return 0;
199     
200     // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
201     // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
202     // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
203     // for more information.
204     const float duration = buffer->duration() / 1000.0f;
205     if (duration < 0.011f)
206         return 0.100f;
207     return duration;
208 }
209
210 NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel, const std::optional<IntSize>&)
211 {
212     // Zero-height images can cause problems for some ports. If we have an empty image dimension, just bail.
213     if (size().isEmpty())
214         return nullptr;
215
216     ImageFrame* buffer = frameBufferAtIndex(index);
217     if (!buffer || buffer->isEmpty() || !buffer->hasBackingStore())
218         return nullptr;
219
220     // Return the buffer contents as a native image. For some ports, the data
221     // is already in a native container, and this just increments its refcount.
222     return buffer->backingStore()->image();
223 }
224
225 void ImageDecoder::prepareScaleDataIfNecessary()
226 {
227     m_scaled = false;
228     m_scaledColumns.clear();
229     m_scaledRows.clear();
230
231     int width = size().width();
232     int height = size().height();
233     int numPixels = height * width;
234     if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
235         return;
236
237     m_scaled = true;
238     double scale = sqrt(m_maxNumPixels / (double)numPixels);
239     fillScaledValues(m_scaledColumns, scale, width);
240     fillScaledValues(m_scaledRows, scale, height);
241 }
242
243 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
244 {
245     return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
246 }
247
248 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
249 {
250     return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
251 }
252
253 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
254 {
255     return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
256 }
257
258 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
259 {
260     return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
261 }
262
263 int ImageDecoder::scaledY(int origY, int searchStart)
264 {
265     return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
266 }
267
268 }