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