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