Remove the memory instrumentation code
[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 #if !PLATFORM(QT) || USE(LIBJPEG)
32 #include "JPEGImageDecoder.h"
33 #endif
34 #include "PNGImageDecoder.h"
35 #include "SharedBuffer.h"
36 #if USE(WEBP)
37 #include "WEBPImageDecoder.h"
38 #endif
39
40 #include <algorithm>
41 #include <cmath>
42
43 using namespace std;
44
45 namespace WebCore {
46
47 namespace {
48
49 unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
50 {
51     unsigned bytesExtracted = 0;
52     const char* moreData;
53     while (unsigned moreDataLength = sharedBuffer.getSomeData(moreData, offset)) {
54         unsigned bytesToCopy = min(bufferLength - bytesExtracted, moreDataLength);
55         memcpy(buffer + bytesExtracted, moreData, bytesToCopy);
56         bytesExtracted += bytesToCopy;
57         if (bytesExtracted == bufferLength)
58             break;
59         offset += bytesToCopy;
60     }
61     return bytesExtracted;
62 }
63
64 bool matchesGIFSignature(char* contents)
65 {
66     return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6);
67 }
68
69 bool matchesPNGSignature(char* contents)
70 {
71     return !memcmp(contents, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8);
72 }
73
74 bool matchesJPEGSignature(char* contents)
75 {
76     return !memcmp(contents, "\xFF\xD8\xFF", 3);
77 }
78
79 #if USE(WEBP)
80 bool matchesWebPSignature(char* contents)
81 {
82     return !memcmp(contents, "RIFF", 4) && !memcmp(contents + 8, "WEBPVP", 6);
83 }
84 #endif
85
86 bool matchesBMPSignature(char* contents)
87 {
88     return !memcmp(contents, "BM", 2);
89 }
90
91 bool matchesICOSignature(char* contents)
92 {
93     return !memcmp(contents, "\x00\x00\x01\x00", 4);
94 }
95
96 bool matchesCURSignature(char* contents)
97 {
98     return !memcmp(contents, "\x00\x00\x02\x00", 4);
99 }
100
101 }
102
103 ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
104 {
105     static const unsigned lengthOfLongestSignature = 14; // To wit: "RIFF????WEBPVP"
106     char contents[lengthOfLongestSignature];
107     unsigned length = copyFromSharedBuffer(contents, lengthOfLongestSignature, data, 0);
108     if (length < lengthOfLongestSignature)
109         return 0;
110
111     if (matchesGIFSignature(contents))
112         return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);
113
114 #if !PLATFORM(QT) || (PLATFORM(QT) && USE(LIBPNG))
115     if (matchesPNGSignature(contents))
116         return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption);
117
118     if (matchesICOSignature(contents) || matchesCURSignature(contents))
119         return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption);
120 #endif
121
122 #if !PLATFORM(QT) || (PLATFORM(QT) && USE(LIBJPEG))
123     if (matchesJPEGSignature(contents))
124         return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption);
125 #endif
126
127 #if USE(WEBP)
128     if (matchesWebPSignature(contents))
129         return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption);
130 #endif
131
132     if (matchesBMPSignature(contents))
133         return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption);
134
135 #if PLATFORM(QT)
136     return new ImageDecoderQt(alphaOption, gammaAndColorProfileOption);
137 #endif
138     return 0;
139 }
140
141 #if !USE(SKIA)
142
143 ImageFrame::ImageFrame()
144     : m_hasAlpha(false)
145     , m_status(FrameEmpty)
146     , m_duration(0)
147     , m_disposalMethod(DisposeNotSpecified)
148     , m_premultiplyAlpha(true)
149 {
150
151
152 ImageFrame& ImageFrame::operator=(const ImageFrame& other)
153 {
154     if (this == &other)
155         return *this;
156
157     copyBitmapData(other);
158     setOriginalFrameRect(other.originalFrameRect());
159     setStatus(other.status());
160     setDuration(other.duration());
161     setDisposalMethod(other.disposalMethod());
162     setPremultiplyAlpha(other.premultiplyAlpha());
163     return *this;
164 }
165
166 void ImageFrame::clearPixelData()
167 {
168     m_backingStore.clear();
169     m_bytes = 0;
170     m_status = FrameEmpty;
171     // NOTE: Do not reset other members here; clearFrameBufferCache() calls this
172     // to free the bitmap data, but other functions like initFrameBuffer() and
173     // frameComplete() may still need to read other metadata out of this frame
174     // later.
175 }
176
177 void ImageFrame::zeroFillPixelData()
178 {
179     memset(m_bytes, 0, m_size.width() * m_size.height() * sizeof(PixelData));
180     m_hasAlpha = true;
181 }
182
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
195 bool ImageFrame::setSize(int newWidth, int newHeight)
196 {
197     ASSERT(!width() && !height());
198     size_t backingStoreSize = newWidth * newHeight;
199     if (!m_backingStore.tryReserveCapacity(backingStoreSize))
200         return false;
201     m_backingStore.resize(backingStoreSize);
202     m_bytes = m_backingStore.data();
203     m_size = IntSize(newWidth, newHeight);
204
205     zeroFillPixelData();
206     return true;
207 }
208
209 bool ImageFrame::hasAlpha() const
210 {
211     return m_hasAlpha;
212 }
213
214 void ImageFrame::setHasAlpha(bool alpha)
215 {
216     m_hasAlpha = alpha;
217 }
218
219 void ImageFrame::setColorProfile(const ColorProfile& colorProfile)
220 {
221     m_colorProfile = colorProfile;
222 }
223
224 void ImageFrame::setStatus(FrameStatus status)
225 {
226     m_status = status;
227 }
228
229 #endif
230
231 namespace {
232
233 enum MatchType {
234     Exact,
235     UpperBound,
236     LowerBound
237 };
238
239 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
240 {
241     double inflateRate = 1. / scaleRate;
242     scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
243     for (int scaledIndex = 0; ; ++scaledIndex) {
244         int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
245         if (index >= length)
246             break;
247         scaledValues.append(index);
248     }
249 }
250
251 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
252 {
253     if (scaledValues.isEmpty())
254         return valueToMatch;
255
256     const int* dataStart = scaledValues.data();
257     const int* dataEnd = dataStart + scaledValues.size();
258     const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
259     switch (type) {
260     case Exact:
261         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
262     case LowerBound:
263         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
264     case UpperBound:
265     default:
266         return matched != dataEnd ? matched - dataStart : -1;
267     }
268 }
269
270 }
271
272 bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const
273 {
274     if (m_frameBufferCache.size() <= index)
275         return true;
276     if (m_frameBufferCache[index].status() == ImageFrame::FrameComplete)
277         return m_frameBufferCache[index].hasAlpha();
278     return true;
279 }
280
281 unsigned ImageDecoder::frameBytesAtIndex(size_t index) const
282 {
283     if (m_frameBufferCache.size() <= index)
284         return 0;
285     // FIXME: Use the dimension of the requested frame.
286     return m_size.area() * sizeof(ImageFrame::PixelData);
287 }
288
289 void ImageDecoder::prepareScaleDataIfNecessary()
290 {
291     m_scaled = false;
292     m_scaledColumns.clear();
293     m_scaledRows.clear();
294
295     int width = size().width();
296     int height = size().height();
297     int numPixels = height * width;
298     if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
299         return;
300
301     m_scaled = true;
302     double scale = sqrt(m_maxNumPixels / (double)numPixels);
303     fillScaledValues(m_scaledColumns, scale, width);
304     fillScaledValues(m_scaledRows, scale, height);
305 }
306
307 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
308 {
309     return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
310 }
311
312 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
313 {
314     return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
315 }
316
317 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
318 {
319     return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
320 }
321
322 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
323 {
324     return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
325 }
326
327 int ImageDecoder::scaledY(int origY, int searchStart)
328 {
329     return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
330 }
331
332 }