663f6d8793a8358734fe658f6be9673305201c12
[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 static unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer)
46 {
47     unsigned bytesExtracted = 0;
48     for (const auto& segment : sharedBuffer) {
49         if (bytesExtracted + segment->size() <= bufferLength) {
50             memcpy(buffer + bytesExtracted, segment->data(), segment->size());
51             bytesExtracted += segment->size();
52         } else {
53             ASSERT(bufferLength - bytesExtracted < segment->size());
54             memcpy(buffer + bytesExtracted, segment->data(), bufferLength - bytesExtracted);
55             bytesExtracted = bufferLength;
56             break;
57         }
58     }
59     return bytesExtracted;
60 }
61
62 bool matchesGIFSignature(char* contents)
63 {
64     return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6);
65 }
66
67 bool matchesPNGSignature(char* contents)
68 {
69     return !memcmp(contents, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8);
70 }
71
72 bool matchesJPEGSignature(char* contents)
73 {
74     return !memcmp(contents, "\xFF\xD8\xFF", 3);
75 }
76
77 #if USE(WEBP)
78 bool matchesWebPSignature(char* contents)
79 {
80     return !memcmp(contents, "RIFF", 4) && !memcmp(contents + 8, "WEBPVP", 6);
81 }
82 #endif
83
84 bool matchesBMPSignature(char* contents)
85 {
86     return !memcmp(contents, "BM", 2);
87 }
88
89 bool matchesICOSignature(char* contents)
90 {
91     return !memcmp(contents, "\x00\x00\x01\x00", 4);
92 }
93
94 bool matchesCURSignature(char* contents)
95 {
96     return !memcmp(contents, "\x00\x00\x02\x00", 4);
97 }
98
99 }
100
101 RefPtr<ImageDecoder> ImageDecoder::create(const SharedBuffer& data, AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
102 {
103     static const unsigned lengthOfLongestSignature = 14; // To wit: "RIFF????WEBPVP"
104     char contents[lengthOfLongestSignature];
105     unsigned length = copyFromSharedBuffer(contents, lengthOfLongestSignature, data);
106     if (length < lengthOfLongestSignature)
107         return nullptr;
108
109     if (matchesGIFSignature(contents))
110         return adoptRef(*new GIFImageDecoder(alphaOption, gammaAndColorProfileOption));
111
112     if (matchesPNGSignature(contents))
113         return adoptRef(*new PNGImageDecoder(alphaOption, gammaAndColorProfileOption));
114
115     if (matchesICOSignature(contents) || matchesCURSignature(contents))
116         return adoptRef(*new ICOImageDecoder(alphaOption, gammaAndColorProfileOption));
117
118     if (matchesJPEGSignature(contents))
119         return adoptRef(*new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption));
120
121 #if USE(WEBP)
122     if (matchesWebPSignature(contents))
123         return adoptRef(*new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption));
124 #endif
125
126     if (matchesBMPSignature(contents))
127         return adoptRef(*new BMPImageDecoder(alphaOption, gammaAndColorProfileOption));
128
129     return nullptr;
130 }
131
132 namespace {
133
134 enum MatchType {
135     Exact,
136     UpperBound,
137     LowerBound
138 };
139
140 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
141 {
142     double inflateRate = 1. / scaleRate;
143     scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
144     for (int scaledIndex = 0; ; ++scaledIndex) {
145         int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
146         if (index >= length)
147             break;
148         scaledValues.append(index);
149     }
150 }
151
152 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
153 {
154     if (scaledValues.isEmpty())
155         return valueToMatch;
156
157     const int* dataStart = scaledValues.data();
158     const int* dataEnd = dataStart + scaledValues.size();
159     const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
160     switch (type) {
161     case Exact:
162         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
163     case LowerBound:
164         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
165     case UpperBound:
166     default:
167         return matched != dataEnd ? matched - dataStart : -1;
168     }
169 }
170
171 }
172
173 bool ImageDecoder::frameIsCompleteAtIndex(size_t index)
174 {
175     ImageFrame* buffer = frameBufferAtIndex(index);
176     return buffer && buffer->isComplete();
177 }
178
179 bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const
180 {
181     if (m_frameBufferCache.size() <= index)
182         return true;
183     if (m_frameBufferCache[index].isComplete())
184         return m_frameBufferCache[index].hasAlpha();
185     return true;
186 }
187
188 unsigned ImageDecoder::frameBytesAtIndex(size_t index) const
189 {
190     if (m_frameBufferCache.size() <= index)
191         return 0;
192     // FIXME: Use the dimension of the requested frame.
193     return (m_size.area() * sizeof(RGBA32)).unsafeGet();
194 }
195
196 float ImageDecoder::frameDurationAtIndex(size_t index)
197 {
198     ImageFrame* buffer = frameBufferAtIndex(index);
199     if (!buffer || buffer->isEmpty())
200         return 0;
201     
202     // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
203     // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
204     // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
205     // for more information.
206     const float duration = buffer->duration() / 1000.0f;
207     if (duration < 0.011f)
208         return 0.100f;
209     return duration;
210 }
211
212 NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel, const DecodingOptions&)
213 {
214     // Zero-height images can cause problems for some ports. If we have an empty image dimension, just bail.
215     if (size().isEmpty())
216         return nullptr;
217
218     ImageFrame* buffer = frameBufferAtIndex(index);
219     if (!buffer || buffer->isEmpty() || !buffer->hasBackingStore())
220         return nullptr;
221
222     // Return the buffer contents as a native image. For some ports, the data
223     // is already in a native container, and this just increments its refcount.
224     return buffer->backingStore()->image();
225 }
226
227 void ImageDecoder::prepareScaleDataIfNecessary()
228 {
229     m_scaled = false;
230     m_scaledColumns.clear();
231     m_scaledRows.clear();
232
233     int width = size().width();
234     int height = size().height();
235     int numPixels = height * width;
236     if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
237         return;
238
239     m_scaled = true;
240     double scale = sqrt(m_maxNumPixels / (double)numPixels);
241     fillScaledValues(m_scaledColumns, scale, width);
242     fillScaledValues(m_scaledRows, scale, height);
243 }
244
245 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
246 {
247     return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
248 }
249
250 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
251 {
252     return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
253 }
254
255 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
256 {
257     return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
258 }
259
260 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
261 {
262     return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
263 }
264
265 int ImageDecoder::scaledY(int origY, int searchStart)
266 {
267     return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
268 }
269
270 }