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 #include "WEBPImageDecoder.h"
35 #include "SharedBuffer.h"
36
37 using namespace std;
38
39 namespace WebCore {
40
41 namespace {
42
copyFromSharedBuffer(char * buffer,unsigned bufferLength,const SharedBuffer & sharedBuffer,unsigned offset)43 unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
44 {
45 unsigned bytesExtracted = 0;
46 const char* moreData;
47 while (unsigned moreDataLength = sharedBuffer.getSomeData(moreData, offset)) {
48 unsigned bytesToCopy = min(bufferLength - bytesExtracted, moreDataLength);
49 memcpy(buffer + bytesExtracted, moreData, bytesToCopy);
50 bytesExtracted += bytesToCopy;
51 if (bytesExtracted == bufferLength)
52 break;
53 offset += bytesToCopy;
54 }
55 return bytesExtracted;
56 }
57
matchesGIFSignature(char * contents)58 bool matchesGIFSignature(char* contents)
59 {
60 return !memcmp(contents, "GIF8", 4);
61 }
62
matchesPNGSignature(char * contents)63 bool matchesPNGSignature(char* contents)
64 {
65 return !memcmp(contents, "\x89\x50\x4E\x47", 4);
66 }
67
matchesJPEGSignature(char * contents)68 bool matchesJPEGSignature(char* contents)
69 {
70 return !memcmp(contents, "\xFF\xD8\xFF", 3);
71 }
72
73 #if USE(WEBP)
matchesWebPSignature(char * contents)74 bool matchesWebPSignature(char* contents)
75 {
76 return !memcmp(contents, "RIFF", 4) && !memcmp(contents + 8, "WEBPVP", 6);
77 }
78 #endif
79
matchesBMPSignature(char * contents)80 bool matchesBMPSignature(char* contents)
81 {
82 return !memcmp(contents, "BM", 2);
83 }
84
matchesICOSignature(char * contents)85 bool matchesICOSignature(char* contents)
86 {
87 return !memcmp(contents, "\x00\x00\x01\x00", 4);
88 }
89
matchesCURSignature(char * contents)90 bool matchesCURSignature(char* contents)
91 {
92 return !memcmp(contents, "\x00\x00\x02\x00", 4);
93 }
94
95 }
96
97 #if !OS(ANDROID)
98 // This method requires BMPImageDecoder, PNGImageDecoder, ICOImageDecoder and
99 // JPEGDecoder, which aren't used on Android, and which don't all compile.
100 // TODO: Find a better fix.
create(const SharedBuffer & data,ImageSource::AlphaOption alphaOption,ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)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 return 0;
130 }
131 #endif // !OS(ANDROID)
132
133 #if !USE(SKIA)
134
ImageFrame()135 ImageFrame::ImageFrame()
136 : m_hasAlpha(false)
137 , m_status(FrameEmpty)
138 , m_duration(0)
139 , m_disposalMethod(DisposeNotSpecified)
140 , m_premultiplyAlpha(true)
141 {
142 }
143
operator =(const ImageFrame & other)144 ImageFrame& ImageFrame::operator=(const ImageFrame& other)
145 {
146 if (this == &other)
147 return *this;
148
149 copyReferenceToBitmapData(other);
150 setOriginalFrameRect(other.originalFrameRect());
151 setStatus(other.status());
152 setDuration(other.duration());
153 setDisposalMethod(other.disposalMethod());
154 setPremultiplyAlpha(other.premultiplyAlpha());
155 return *this;
156 }
157
clearPixelData()158 void ImageFrame::clearPixelData()
159 {
160 m_backingStore.clear();
161 m_bytes = 0;
162 m_status = FrameEmpty;
163 // NOTE: Do not reset other members here; clearFrameBufferCache() calls this
164 // to free the bitmap data, but other functions like initFrameBuffer() and
165 // frameComplete() may still need to read other metadata out of this frame
166 // later.
167 }
168
zeroFillPixelData()169 void ImageFrame::zeroFillPixelData()
170 {
171 memset(m_bytes, 0, m_size.width() * m_size.height() * sizeof(PixelData));
172 m_hasAlpha = true;
173 }
174
175 #if !USE(CG)
176
copyReferenceToBitmapData(const ImageFrame & other)177 void ImageFrame::copyReferenceToBitmapData(const ImageFrame& other)
178 {
179 ASSERT(this != &other);
180 copyBitmapData(other);
181 }
182
copyBitmapData(const ImageFrame & other)183 bool ImageFrame::copyBitmapData(const ImageFrame& other)
184 {
185 if (this == &other)
186 return true;
187
188 m_backingStore = other.m_backingStore;
189 m_bytes = m_backingStore.data();
190 m_size = other.m_size;
191 setHasAlpha(other.m_hasAlpha);
192 return true;
193 }
194
setSize(int newWidth,int newHeight)195 bool ImageFrame::setSize(int newWidth, int newHeight)
196 {
197 // NOTE: This has no way to check for allocation failure if the requested
198 // size was too big...
199 m_backingStore.resize(newWidth * newHeight);
200 m_bytes = m_backingStore.data();
201 m_size = IntSize(newWidth, newHeight);
202
203 zeroFillPixelData();
204
205 return true;
206 }
207
208 #endif
209
hasAlpha() const210 bool ImageFrame::hasAlpha() const
211 {
212 return m_hasAlpha;
213 }
214
setHasAlpha(bool alpha)215 void ImageFrame::setHasAlpha(bool alpha)
216 {
217 m_hasAlpha = alpha;
218 }
219
setColorProfile(const ColorProfile & colorProfile)220 void ImageFrame::setColorProfile(const ColorProfile& colorProfile)
221 {
222 m_colorProfile = colorProfile;
223 }
224
setStatus(FrameStatus status)225 void ImageFrame::setStatus(FrameStatus status)
226 {
227 m_status = status;
228 }
229
width() const230 int ImageFrame::width() const
231 {
232 return m_size.width();
233 }
234
height() const235 int ImageFrame::height() const
236 {
237 return m_size.height();
238 }
239
240 #endif
241
242 namespace {
243
244 enum MatchType {
245 Exact,
246 UpperBound,
247 LowerBound
248 };
249
fillScaledValues(Vector<int> & scaledValues,double scaleRate,int length)250 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
251 {
252 double inflateRate = 1. / scaleRate;
253 scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
254 for (int scaledIndex = 0; ; ++scaledIndex) {
255 int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
256 if (index >= length)
257 break;
258 scaledValues.append(index);
259 }
260 }
261
getScaledValue(const Vector<int> & scaledValues,int valueToMatch,int searchStart)262 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
263 {
264 if (scaledValues.isEmpty())
265 return valueToMatch;
266
267 const int* dataStart = scaledValues.data();
268 const int* dataEnd = dataStart + scaledValues.size();
269 const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
270 switch (type) {
271 case Exact:
272 return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
273 case LowerBound:
274 return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
275 case UpperBound:
276 default:
277 return matched != dataEnd ? matched - dataStart : -1;
278 }
279 }
280
281 }
282
prepareScaleDataIfNecessary()283 void ImageDecoder::prepareScaleDataIfNecessary()
284 {
285 m_scaled = false;
286 m_scaledColumns.clear();
287 m_scaledRows.clear();
288
289 int width = size().width();
290 int height = size().height();
291 int numPixels = height * width;
292 if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
293 return;
294
295 m_scaled = true;
296 double scale = sqrt(m_maxNumPixels / (double)numPixels);
297 fillScaledValues(m_scaledColumns, scale, width);
298 fillScaledValues(m_scaledRows, scale, height);
299 }
300
upperBoundScaledX(int origX,int searchStart)301 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
302 {
303 return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
304 }
305
lowerBoundScaledX(int origX,int searchStart)306 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
307 {
308 return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
309 }
310
upperBoundScaledY(int origY,int searchStart)311 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
312 {
313 return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
314 }
315
lowerBoundScaledY(int origY,int searchStart)316 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
317 {
318 return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
319 }
320
scaledY(int origY,int searchStart)321 int ImageDecoder::scaledY(int origY, int searchStart)
322 {
323 return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
324 }
325
326 }
327