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