2 * Copyright (C) 2008-2009 Torch Mobile, Inc.
3 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
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.
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.
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.
23 #include "ImageDecoder.h"
25 #include "BMPImageDecoder.h"
26 #include "GIFImageDecoder.h"
27 #include "ICOImageDecoder.h"
29 #include "ImageDecoderQt.h"
31 #if !PLATFORM(QT) || USE(LIBJPEG)
32 #include "JPEGImageDecoder.h"
34 #include "PNGImageDecoder.h"
35 #include "SharedBuffer.h"
37 #include "WEBPImageDecoder.h"
49 unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
51 unsigned bytesExtracted = 0;
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)
59 offset += bytesToCopy;
61 return bytesExtracted;
64 bool matchesGIFSignature(char* contents)
66 return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6);
69 bool matchesPNGSignature(char* contents)
71 return !memcmp(contents, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8);
74 bool matchesJPEGSignature(char* contents)
76 return !memcmp(contents, "\xFF\xD8\xFF", 3);
80 bool matchesWebPSignature(char* contents)
82 return !memcmp(contents, "RIFF", 4) && !memcmp(contents + 8, "WEBPVP", 6);
86 bool matchesBMPSignature(char* contents)
88 return !memcmp(contents, "BM", 2);
91 bool matchesICOSignature(char* contents)
93 return !memcmp(contents, "\x00\x00\x01\x00", 4);
96 bool matchesCURSignature(char* contents)
98 return !memcmp(contents, "\x00\x00\x02\x00", 4);
103 ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
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)
111 if (matchesGIFSignature(contents))
112 return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);
114 #if !PLATFORM(QT) || (PLATFORM(QT) && USE(LIBPNG))
115 if (matchesPNGSignature(contents))
116 return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption);
118 if (matchesICOSignature(contents) || matchesCURSignature(contents))
119 return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption);
122 #if !PLATFORM(QT) || (PLATFORM(QT) && USE(LIBJPEG))
123 if (matchesJPEGSignature(contents))
124 return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption);
128 if (matchesWebPSignature(contents))
129 return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption);
132 if (matchesBMPSignature(contents))
133 return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption);
136 return new ImageDecoderQt(alphaOption, gammaAndColorProfileOption);
141 ImageFrame::ImageFrame()
143 , m_status(FrameEmpty)
145 , m_disposalMethod(DisposeNotSpecified)
146 , m_premultiplyAlpha(true)
150 ImageFrame& ImageFrame::operator=(const ImageFrame& other)
155 copyBitmapData(other);
156 setOriginalFrameRect(other.originalFrameRect());
157 setStatus(other.status());
158 setDuration(other.duration());
159 setDisposalMethod(other.disposalMethod());
160 setPremultiplyAlpha(other.premultiplyAlpha());
164 void ImageFrame::clearPixelData()
166 m_backingStore.clear();
168 m_status = FrameEmpty;
169 // NOTE: Do not reset other members here; clearFrameBufferCache() calls this
170 // to free the bitmap data, but other functions like initFrameBuffer() and
171 // frameComplete() may still need to read other metadata out of this frame
175 void ImageFrame::zeroFillPixelData()
177 memset(m_bytes, 0, m_size.width() * m_size.height() * sizeof(PixelData));
181 bool ImageFrame::copyBitmapData(const ImageFrame& other)
186 m_backingStore = other.m_backingStore;
187 m_bytes = m_backingStore.data();
188 m_size = other.m_size;
189 setHasAlpha(other.m_hasAlpha);
193 bool ImageFrame::setSize(int newWidth, int newHeight)
195 ASSERT(!width() && !height());
196 size_t backingStoreSize = newWidth * newHeight;
197 if (!m_backingStore.tryReserveCapacity(backingStoreSize))
199 m_backingStore.resize(backingStoreSize);
200 m_bytes = m_backingStore.data();
201 m_size = IntSize(newWidth, newHeight);
207 bool ImageFrame::hasAlpha() const
212 void ImageFrame::setHasAlpha(bool alpha)
217 void ImageFrame::setColorProfile(const ColorProfile& colorProfile)
219 m_colorProfile = colorProfile;
222 void ImageFrame::setStatus(FrameStatus status)
235 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
237 double inflateRate = 1. / scaleRate;
238 scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
239 for (int scaledIndex = 0; ; ++scaledIndex) {
240 int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
243 scaledValues.append(index);
247 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
249 if (scaledValues.isEmpty())
252 const int* dataStart = scaledValues.data();
253 const int* dataEnd = dataStart + scaledValues.size();
254 const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
257 return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
259 return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
262 return matched != dataEnd ? matched - dataStart : -1;
268 bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const
270 if (m_frameBufferCache.size() <= index)
272 if (m_frameBufferCache[index].status() == ImageFrame::FrameComplete)
273 return m_frameBufferCache[index].hasAlpha();
277 unsigned ImageDecoder::frameBytesAtIndex(size_t index) const
279 if (m_frameBufferCache.size() <= index)
281 // FIXME: Use the dimension of the requested frame.
282 return m_size.area() * sizeof(ImageFrame::PixelData);
285 void ImageDecoder::prepareScaleDataIfNecessary()
288 m_scaledColumns.clear();
289 m_scaledRows.clear();
291 int width = size().width();
292 int height = size().height();
293 int numPixels = height * width;
294 if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
298 double scale = sqrt(m_maxNumPixels / (double)numPixels);
299 fillScaledValues(m_scaledColumns, scale, width);
300 fillScaledValues(m_scaledRows, scale, height);
303 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
305 return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
308 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
310 return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
313 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
315 return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
318 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
320 return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
323 int ImageDecoder::scaledY(int origY, int searchStart)
325 return getScaledValue<Exact>(m_scaledRows, origY, searchStart);