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 37using namespace std; 38 39namespace WebCore { 40 41namespace { 42 43unsigned 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 58bool matchesGIFSignature(char* contents) 59{ 60 return !memcmp(contents, "GIF8", 4); 61} 62 63bool matchesPNGSignature(char* contents) 64{ 65 return !memcmp(contents, "\x89\x50\x4E\x47", 4); 66} 67 68bool matchesJPEGSignature(char* contents) 69{ 70 return !memcmp(contents, "\xFF\xD8\xFF", 3); 71} 72 73#if USE(WEBP) 74bool matchesWebPSignature(char* contents) 75{ 76 return !memcmp(contents, "RIFF", 4) && !memcmp(contents + 8, "WEBPVP", 6); 77} 78#endif 79 80bool matchesBMPSignature(char* contents) 81{ 82 return !memcmp(contents, "BM", 2); 83} 84 85bool matchesICOSignature(char* contents) 86{ 87 return !memcmp(contents, "\x00\x00\x01\x00", 4); 88} 89 90bool 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. 101ImageDecoder* 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 135ImageFrame::ImageFrame() 136 : m_hasAlpha(false) 137 , m_status(FrameEmpty) 138 , m_duration(0) 139 , m_disposalMethod(DisposeNotSpecified) 140 , m_premultiplyAlpha(true) 141{ 142} 143 144ImageFrame& 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 158void 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 169void 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 177void ImageFrame::copyReferenceToBitmapData(const ImageFrame& other) 178{ 179 ASSERT(this != &other); 180 copyBitmapData(other); 181} 182 183bool 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 195bool 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 210bool ImageFrame::hasAlpha() const 211{ 212 return m_hasAlpha; 213} 214 215void ImageFrame::setHasAlpha(bool alpha) 216{ 217 m_hasAlpha = alpha; 218} 219 220void ImageFrame::setColorProfile(const ColorProfile& colorProfile) 221{ 222 m_colorProfile = colorProfile; 223} 224 225void ImageFrame::setStatus(FrameStatus status) 226{ 227 m_status = status; 228} 229 230int ImageFrame::width() const 231{ 232 return m_size.width(); 233} 234 235int ImageFrame::height() const 236{ 237 return m_size.height(); 238} 239 240#endif 241 242namespace { 243 244enum MatchType { 245 Exact, 246 UpperBound, 247 LowerBound 248}; 249 250inline 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 262template <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 283void 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 301int ImageDecoder::upperBoundScaledX(int origX, int searchStart) 302{ 303 return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart); 304} 305 306int ImageDecoder::lowerBoundScaledX(int origX, int searchStart) 307{ 308 return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart); 309} 310 311int ImageDecoder::upperBoundScaledY(int origY, int searchStart) 312{ 313 return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart); 314} 315 316int ImageDecoder::lowerBoundScaledY(int origY, int searchStart) 317{ 318 return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart); 319} 320 321int ImageDecoder::scaledY(int origY, int searchStart) 322{ 323 return getScaledValue<Exact>(m_scaledRows, origY, searchStart); 324} 325 326} 327