[Qt] Set WebCore imagedecoders as default and add fallback to QImageDecoder
[WebKit-https.git] / Source / WebCore / platform / image-decoders / ImageDecoder.cpp
1 /*
2  * Copyright (C) 2008-2009 Torch Mobile, Inc.
3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public License
16  *  along with this library; see the file COPYING.LIB.  If not, write to
17  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  *  Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #include "config.h"
23 #include "ImageDecoder.h"
24
25 #include "BMPImageDecoder.h"
26 #include "GIFImageDecoder.h"
27 #include "ICOImageDecoder.h"
28 #if PLATFORM(QT)
29 #include "ImageDecoderQt.h"
30 #endif
31 #include "JPEGImageDecoder.h"
32 #include "PNGImageDecoder.h"
33 #include "SharedBuffer.h"
34 #if USE(WEBP)
35 #include "WEBPImageDecoder.h"
36 #endif
37
38 #include <algorithm>
39 #include <cmath>
40
41 using namespace std;
42
43 namespace WebCore {
44
45 namespace {
46
47 unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
48 {
49     unsigned bytesExtracted = 0;
50     const char* moreData;
51     while (unsigned moreDataLength = sharedBuffer.getSomeData(moreData, offset)) {
52         unsigned bytesToCopy = min(bufferLength - bytesExtracted, moreDataLength);
53         memcpy(buffer + bytesExtracted, moreData, bytesToCopy);
54         bytesExtracted += bytesToCopy;
55         if (bytesExtracted == bufferLength)
56             break;
57         offset += bytesToCopy;
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 ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
102 {
103     static const unsigned lengthOfLongestSignature = 14; // To wit: "RIFF????WEBPVP"
104     char contents[lengthOfLongestSignature];
105     unsigned length = copyFromSharedBuffer(contents, lengthOfLongestSignature, data, 0);
106     if (length < lengthOfLongestSignature)
107         return 0;
108
109     if (matchesGIFSignature(contents))
110         return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);
111
112     if (matchesPNGSignature(contents))
113         return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption);
114
115     if (matchesJPEGSignature(contents))
116         return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption);
117
118 #if USE(WEBP)
119     if (matchesWebPSignature(contents))
120         return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption);
121 #endif
122
123     if (matchesBMPSignature(contents))
124         return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption);
125
126     if (matchesICOSignature(contents) || matchesCURSignature(contents))
127         return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption);
128
129 #if PLATFORM(QT)
130     return new ImageDecoderQt(alphaOption, gammaAndColorProfileOption);
131 #endif
132     return 0;
133 }
134
135 #if !USE(SKIA)
136
137 ImageFrame::ImageFrame()
138     : m_hasAlpha(false)
139     , m_status(FrameEmpty)
140     , m_duration(0)
141     , m_disposalMethod(DisposeNotSpecified)
142     , m_premultiplyAlpha(true)
143 {
144
145
146 ImageFrame& ImageFrame::operator=(const ImageFrame& other)
147 {
148     if (this == &other)
149         return *this;
150
151     copyReferenceToBitmapData(other);
152     setOriginalFrameRect(other.originalFrameRect());
153     setStatus(other.status());
154     setDuration(other.duration());
155     setDisposalMethod(other.disposalMethod());
156     setPremultiplyAlpha(other.premultiplyAlpha());
157     return *this;
158 }
159
160 void ImageFrame::clearPixelData()
161 {
162     m_backingStore.clear();
163     m_bytes = 0;
164     m_status = FrameEmpty;
165     // NOTE: Do not reset other members here; clearFrameBufferCache() calls this
166     // to free the bitmap data, but other functions like initFrameBuffer() and
167     // frameComplete() may still need to read other metadata out of this frame
168     // later.
169 }
170
171 void ImageFrame::zeroFillPixelData()
172 {
173     memset(m_bytes, 0, m_size.width() * m_size.height() * sizeof(PixelData));
174     m_hasAlpha = true;
175 }
176
177 #if !USE(CG)
178
179 void ImageFrame::copyReferenceToBitmapData(const ImageFrame& other)
180 {
181     ASSERT(this != &other);
182     copyBitmapData(other);
183 }
184
185 bool ImageFrame::copyBitmapData(const ImageFrame& other)
186 {
187     if (this == &other)
188         return true;
189
190     m_backingStore = other.m_backingStore;
191     m_bytes = m_backingStore.data();
192     m_size = other.m_size;
193     setHasAlpha(other.m_hasAlpha);
194     return true;
195 }
196
197 bool ImageFrame::setSize(int newWidth, int newHeight)
198 {
199     ASSERT(!width() && !height());
200     size_t backingStoreSize = newWidth * newHeight;
201     if (!m_backingStore.tryReserveCapacity(backingStoreSize))
202         return false;
203     m_backingStore.resize(backingStoreSize);
204     m_bytes = m_backingStore.data();
205     m_size = IntSize(newWidth, newHeight);
206
207     zeroFillPixelData();
208     return true;
209 }
210
211 #endif
212
213 bool ImageFrame::hasAlpha() const
214 {
215     return m_hasAlpha;
216 }
217
218 void ImageFrame::setHasAlpha(bool alpha)
219 {
220     m_hasAlpha = alpha;
221 }
222
223 void ImageFrame::setColorProfile(const ColorProfile& colorProfile)
224 {
225     m_colorProfile = colorProfile;
226 }
227
228 void ImageFrame::setStatus(FrameStatus status)
229 {
230     m_status = status;
231 }
232
233 int ImageFrame::width() const
234 {
235     return m_size.width();
236 }
237
238 int ImageFrame::height() const
239 {
240     return m_size.height();
241 }
242
243 #endif
244
245 namespace {
246
247 enum MatchType {
248     Exact,
249     UpperBound,
250     LowerBound
251 };
252
253 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
254 {
255     double inflateRate = 1. / scaleRate;
256     scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
257     for (int scaledIndex = 0; ; ++scaledIndex) {
258         int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
259         if (index >= length)
260             break;
261         scaledValues.append(index);
262     }
263 }
264
265 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
266 {
267     if (scaledValues.isEmpty())
268         return valueToMatch;
269
270     const int* dataStart = scaledValues.data();
271     const int* dataEnd = dataStart + scaledValues.size();
272     const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
273     switch (type) {
274     case Exact:
275         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
276     case LowerBound:
277         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
278     case UpperBound:
279     default:
280         return matched != dataEnd ? matched - dataStart : -1;
281     }
282 }
283
284 }
285
286 void ImageDecoder::prepareScaleDataIfNecessary()
287 {
288     m_scaled = false;
289     m_scaledColumns.clear();
290     m_scaledRows.clear();
291
292     int width = size().width();
293     int height = size().height();
294     int numPixels = height * width;
295     if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
296         return;
297
298     m_scaled = true;
299     double scale = sqrt(m_maxNumPixels / (double)numPixels);
300     fillScaledValues(m_scaledColumns, scale, width);
301     fillScaledValues(m_scaledRows, scale, height);
302 }
303
304 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
305 {
306     return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
307 }
308
309 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
310 {
311     return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
312 }
313
314 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
315 {
316     return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
317 }
318
319 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
320 {
321     return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
322 }
323
324 int ImageDecoder::scaledY(int origY, int searchStart)
325 {
326     return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
327 }
328
329 }