[chromium] Remove ImageDecoderCG.cpp from platform/image-decoders
[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
24 #include "ImageDecoder.h"
25
26 #include <algorithm>
27 #include <cmath>
28
29 #include "BMPImageDecoder.h"
30 #include "GIFImageDecoder.h"
31 #include "ICOImageDecoder.h"
32 #include "JPEGImageDecoder.h"
33 #include "PNGImageDecoder.h"
34 #if USE(WEBP)
35 #include "WEBPImageDecoder.h"
36 #endif
37 #include "SharedBuffer.h"
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 ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::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 0;
106
107     if (matchesGIFSignature(contents))
108         return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);
109
110     if (matchesPNGSignature(contents))
111         return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption);
112
113     if (matchesJPEGSignature(contents))
114         return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption);
115
116 #if USE(WEBP)
117     if (matchesWebPSignature(contents))
118         return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption);
119 #endif
120
121     if (matchesBMPSignature(contents))
122         return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption);
123
124     if (matchesICOSignature(contents) || matchesCURSignature(contents))
125         return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption);
126
127     return 0;
128 }
129
130 #if !USE(SKIA)
131
132 ImageFrame::ImageFrame()
133     : m_hasAlpha(false)
134     , m_status(FrameEmpty)
135     , m_duration(0)
136     , m_disposalMethod(DisposeNotSpecified)
137     , m_premultiplyAlpha(true)
138 {
139
140
141 ImageFrame& ImageFrame::operator=(const ImageFrame& other)
142 {
143     if (this == &other)
144         return *this;
145
146     copyBitmapData(other);
147     setOriginalFrameRect(other.originalFrameRect());
148     setStatus(other.status());
149     setDuration(other.duration());
150     setDisposalMethod(other.disposalMethod());
151     setPremultiplyAlpha(other.premultiplyAlpha());
152     return *this;
153 }
154
155 void ImageFrame::clearPixelData()
156 {
157     m_backingStore.clear();
158     m_bytes = 0;
159     m_status = FrameEmpty;
160     // NOTE: Do not reset other members here; clearFrameBufferCache() calls this
161     // to free the bitmap data, but other functions like initFrameBuffer() and
162     // frameComplete() may still need to read other metadata out of this frame
163     // later.
164 }
165
166 void ImageFrame::zeroFillPixelData()
167 {
168     memset(m_bytes, 0, m_size.width() * m_size.height() * sizeof(PixelData));
169     m_hasAlpha = true;
170 }
171
172 bool ImageFrame::copyBitmapData(const ImageFrame& other)
173 {
174     if (this == &other)
175         return true;
176
177     m_backingStore = other.m_backingStore;
178     m_bytes = m_backingStore.data();
179     m_size = other.m_size;
180     setHasAlpha(other.m_hasAlpha);
181     return true;
182 }
183
184 bool ImageFrame::setSize(int newWidth, int newHeight)
185 {
186     ASSERT(!width() && !height());
187     size_t backingStoreSize = newWidth * newHeight;
188     if (!m_backingStore.tryReserveCapacity(backingStoreSize))
189         return false;
190     m_backingStore.resize(backingStoreSize);
191     m_bytes = m_backingStore.data();
192     m_size = IntSize(newWidth, newHeight);
193
194     zeroFillPixelData();
195     return true;
196 }
197
198 bool ImageFrame::hasAlpha() const
199 {
200     return m_hasAlpha;
201 }
202
203 void ImageFrame::setHasAlpha(bool alpha)
204 {
205     m_hasAlpha = alpha;
206 }
207
208 void ImageFrame::setColorProfile(const ColorProfile& colorProfile)
209 {
210     m_colorProfile = colorProfile;
211 }
212
213 void ImageFrame::setStatus(FrameStatus status)
214 {
215     m_status = status;
216 }
217
218 int ImageFrame::width() const
219 {
220     return m_size.width();
221 }
222
223 int ImageFrame::height() const
224 {
225     return m_size.height();
226 }
227
228 #endif
229
230 namespace {
231
232 enum MatchType {
233     Exact,
234     UpperBound,
235     LowerBound
236 };
237
238 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
239 {
240     double inflateRate = 1. / scaleRate;
241     scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
242     for (int scaledIndex = 0; ; ++scaledIndex) {
243         int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
244         if (index >= length)
245             break;
246         scaledValues.append(index);
247     }
248 }
249
250 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
251 {
252     if (scaledValues.isEmpty())
253         return valueToMatch;
254
255     const int* dataStart = scaledValues.data();
256     const int* dataEnd = dataStart + scaledValues.size();
257     const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
258     switch (type) {
259     case Exact:
260         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
261     case LowerBound:
262         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
263     case UpperBound:
264     default:
265         return matched != dataEnd ? matched - dataStart : -1;
266     }
267 }
268
269 }
270
271 void ImageDecoder::prepareScaleDataIfNecessary()
272 {
273     m_scaled = false;
274     m_scaledColumns.clear();
275     m_scaledRows.clear();
276
277     int width = size().width();
278     int height = size().height();
279     int numPixels = height * width;
280     if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
281         return;
282
283     m_scaled = true;
284     double scale = sqrt(m_maxNumPixels / (double)numPixels);
285     fillScaledValues(m_scaledColumns, scale, width);
286     fillScaledValues(m_scaledRows, scale, height);
287 }
288
289 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
290 {
291     return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
292 }
293
294 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
295 {
296     return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
297 }
298
299 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
300 {
301     return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
302 }
303
304 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
305 {
306     return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
307 }
308
309 int ImageDecoder::scaledY(int origY, int searchStart)
310 {
311     return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
312 }
313
314 }