Move WebCore into Source
[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 #include "WEBPImageDecoder.h"
35 #include "SharedBuffer.h"
36
37 using namespace std;
38
39 namespace WebCore {
40
41 static unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
42 {
43     unsigned bytesExtracted = 0;
44     const char* moreData;
45     while (unsigned moreDataLength = sharedBuffer.getSomeData(moreData, offset)) {
46         unsigned bytesToCopy = min(bufferLength - bytesExtracted, moreDataLength);
47         memcpy(buffer + bytesExtracted, moreData, bytesToCopy);
48         bytesExtracted += bytesToCopy;
49         if (bytesExtracted == bufferLength)
50             break;
51         offset += bytesToCopy;
52     }
53     return bytesExtracted;
54 }
55
56 ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
57 {
58     // We need at least 4 bytes to figure out what kind of image we're dealing
59     // with.
60     static const unsigned maxMarkerLength = 4;
61     char contents[maxMarkerLength];
62     unsigned length = copyFromSharedBuffer(contents, maxMarkerLength, data, 0);
63     if (length < maxMarkerLength)
64         return 0;
65
66     // GIFs begin with GIF8(7 or 9).
67     if (strncmp(contents, "GIF8", 4) == 0)
68         return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);
69
70     // Test for PNG.
71     if (!memcmp(contents, "\x89\x50\x4E\x47", 4))
72         return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption);
73
74     // JPEG
75     if (!memcmp(contents, "\xFF\xD8\xFF", 3))
76         return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption);
77
78 #if USE(WEBP)
79     if (!memcmp(contents, "RIFF", 4)) {
80         static const unsigned webpExtraMarker = 6;
81         static const unsigned webpExtraMarkeroffset = 8;
82         char header[webpExtraMarker];
83         unsigned length = copyFromSharedBuffer(header, webpExtraMarker, data, webpExtraMarkeroffset);
84         if (length >= webpExtraMarker) {
85             if (!memcmp(header, "WEBPVP", webpExtraMarker))
86                 return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption);
87         }
88     }
89 #endif
90
91     // BMP
92     if (strncmp(contents, "BM", 2) == 0)
93         return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption);
94
95     // ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
96     // CURs begin with 2-byte 0 followed by 2-byte 2.
97     if (!memcmp(contents, "\x00\x00\x01\x00", 4) || !memcmp(contents, "\x00\x00\x02\x00", 4))
98         return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption);
99
100     // Give up. We don't know what the heck this is.
101     return 0;
102 }
103
104 #if !PLATFORM(SKIA)
105
106 RGBA32Buffer::RGBA32Buffer()
107     : m_hasAlpha(false)
108     , m_status(FrameEmpty)
109     , m_duration(0)
110     , m_disposalMethod(DisposeNotSpecified)
111     , m_premultiplyAlpha(true)
112 {
113
114
115 RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
116 {
117     if (this == &other)
118         return *this;
119
120     copyReferenceToBitmapData(other);
121     setRect(other.rect());
122     setStatus(other.status());
123     setDuration(other.duration());
124     setDisposalMethod(other.disposalMethod());
125     setPremultiplyAlpha(other.premultiplyAlpha());
126     return *this;
127 }
128
129 void RGBA32Buffer::clear()
130 {
131     m_backingStore.clear();
132     m_bytes = 0;
133     m_status = FrameEmpty;
134     // NOTE: Do not reset other members here; clearFrameBufferCache() calls this
135     // to free the bitmap data, but other functions like initFrameBuffer() and
136     // frameComplete() may still need to read other metadata out of this frame
137     // later.
138 }
139
140 void RGBA32Buffer::zeroFill()
141 {
142     memset(m_bytes, 0, m_size.width() * m_size.height() * sizeof(PixelData));
143     m_hasAlpha = true;
144 }
145
146 #if !PLATFORM(CG)
147
148 void RGBA32Buffer::copyReferenceToBitmapData(const RGBA32Buffer& other)
149 {
150     ASSERT(this != &other);
151     copyBitmapData(other);
152 }
153
154 bool RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other)
155 {
156     if (this == &other)
157         return true;
158
159     m_backingStore = other.m_backingStore;
160     m_bytes = m_backingStore.data();
161     m_size = other.m_size;
162     setHasAlpha(other.m_hasAlpha);
163     return true;
164 }
165
166 bool RGBA32Buffer::setSize(int newWidth, int newHeight)
167 {
168     // NOTE: This has no way to check for allocation failure if the requested
169     // size was too big...
170     m_backingStore.resize(newWidth * newHeight);
171     m_bytes = m_backingStore.data();
172     m_size = IntSize(newWidth, newHeight);
173
174     // Zero the image.
175     zeroFill();
176
177     return true;
178 }
179
180 #endif
181
182 bool RGBA32Buffer::hasAlpha() const
183 {
184     return m_hasAlpha;
185 }
186
187 void RGBA32Buffer::setHasAlpha(bool alpha)
188 {
189     m_hasAlpha = alpha;
190 }
191
192 void RGBA32Buffer::setColorProfile(const ColorProfile& colorProfile)
193 {
194     m_colorProfile = colorProfile;
195 }
196
197 void RGBA32Buffer::setStatus(FrameStatus status)
198 {
199     m_status = status;
200 }
201
202 int RGBA32Buffer::width() const
203 {
204     return m_size.width();
205 }
206
207 int RGBA32Buffer::height() const
208 {
209     return m_size.height();
210 }
211
212 #endif
213
214 namespace {
215
216 enum MatchType {
217     Exact,
218     UpperBound,
219     LowerBound
220 };
221
222 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
223 {
224     double inflateRate = 1. / scaleRate;
225     scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
226     for (int scaledIndex = 0; ; ++scaledIndex) {
227         int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
228         if (index >= length)
229             break;
230         scaledValues.append(index);
231     }
232 }
233
234 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
235 {
236     if (scaledValues.isEmpty())
237         return valueToMatch;
238
239     const int* dataStart = scaledValues.data();
240     const int* dataEnd = dataStart + scaledValues.size();
241     const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
242     switch (type) {
243     case Exact:
244         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
245     case LowerBound:
246         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
247     case UpperBound:
248     default:
249         return matched != dataEnd ? matched - dataStart : -1;
250     }
251 }
252
253 }
254
255 void ImageDecoder::prepareScaleDataIfNecessary()
256 {
257     m_scaled = false;
258     m_scaledColumns.clear();
259     m_scaledRows.clear();
260
261     int width = size().width();
262     int height = size().height();
263     int numPixels = height * width;
264     if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
265         return;
266
267     m_scaled = true;
268     double scale = sqrt(m_maxNumPixels / (double)numPixels);
269     fillScaledValues(m_scaledColumns, scale, width);
270     fillScaledValues(m_scaledRows, scale, height);
271 }
272
273 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
274 {
275     return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
276 }
277
278 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
279 {
280     return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
281 }
282
283 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
284 {
285     return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
286 }
287
288 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
289 {
290     return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
291 }
292
293 int ImageDecoder::scaledY(int origY, int searchStart)
294 {
295     return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
296 }
297
298 }