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 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. 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 104 RGBA32Buffer::RGBA32Buffer() 105 : m_hasAlpha(false) 106 , m_status(FrameEmpty) 107 , m_duration(0) 108 , m_disposalMethod(DisposeNotSpecified) 109 { 110 } 111 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 122 void RGBA32Buffer::zeroFill() 123 { 124 m_bytes.fill(0); 125 m_hasAlpha = true; 126 } 127 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 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 151 bool RGBA32Buffer::hasAlpha() const 152 { 153 return m_hasAlpha; 154 } 155 156 void RGBA32Buffer::setHasAlpha(bool alpha) 157 { 158 m_hasAlpha = alpha; 159 } 160 161 void RGBA32Buffer::setStatus(FrameStatus status) 162 { 163 m_status = status; 164 } 165 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 179 int RGBA32Buffer::width() const 180 { 181 return m_size.width(); 182 } 183 184 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 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 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 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 251 int ImageDecoder::upperBoundScaledX(int origX, int searchStart) 252 { 253 return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart); 254 } 255 256 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart) 257 { 258 return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart); 259 } 260 261 int ImageDecoder::upperBoundScaledY(int origY, int searchStart) 262 { 263 return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart); 264 } 265 266 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart) 267 { 268 return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart); 269 } 270 271 int ImageDecoder::scaledY(int origY, int searchStart) 272 { 273 return getScaledValue<Exact>(m_scaledRows, origY, searchStart); 274 } 275 276 } 277