1/* 2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 3 * Copyright (C) 2008-2009 Torch Mobile, Inc. 4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. 5 * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#ifndef ImageDecoder_h 30#define ImageDecoder_h 31 32#include "IntRect.h" 33#include "ImageSource.h" 34#include "PlatformScreen.h" 35#include "SharedBuffer.h" 36#include <wtf/Assertions.h> 37#include <wtf/RefPtr.h> 38#include <wtf/Vector.h> 39#include <wtf/text/WTFString.h> 40 41#if USE(QCMSLIB) 42#include "qcms.h" 43#if OS(DARWIN) 44#include "GraphicsContextCG.h" 45#include <ApplicationServices/ApplicationServices.h> 46#include <wtf/RetainPtr.h> 47#endif 48#endif 49 50namespace WebCore { 51 52 // ImageFrame represents the decoded image data. This buffer is what all 53 // decoders write a single frame into. 54 class ImageFrame { 55 public: 56 enum FrameStatus { FrameEmpty, FramePartial, FrameComplete }; 57 enum FrameDisposalMethod { 58 // If you change the numeric values of these, make sure you audit 59 // all users, as some users may cast raw values to/from these 60 // constants. 61 DisposeNotSpecified, // Leave frame in framebuffer 62 DisposeKeep, // Leave frame in framebuffer 63 DisposeOverwriteBgcolor, // Clear frame to transparent 64 DisposeOverwritePrevious // Clear frame to previous framebuffer 65 // contents 66 }; 67 typedef unsigned PixelData; 68 69 ImageFrame(); 70 71 ImageFrame(const ImageFrame& other) { operator=(other); } 72 73 // For backends which refcount their data, this operator doesn't need to 74 // create a new copy of the image data, only increase the ref count. 75 ImageFrame& operator=(const ImageFrame& other); 76 77 // These do not touch other metadata, only the raw pixel data. 78 void clearPixelData(); 79 void zeroFillPixelData(); 80 81 // Makes this frame have an independent copy of the provided image's 82 // pixel data, so that modifications in one frame are not reflected in 83 // the other. Returns whether the copy succeeded. 84 bool copyBitmapData(const ImageFrame&); 85 86 // Copies the pixel data at [(startX, startY), (endX, startY)) to the 87 // same X-coordinates on each subsequent row up to but not including 88 // endY. 89 void copyRowNTimes(int startX, int endX, int startY, int endY) 90 { 91 ASSERT(startX < width()); 92 ASSERT(endX <= width()); 93 ASSERT(startY < height()); 94 ASSERT(endY <= height()); 95 const int rowBytes = (endX - startX) * sizeof(PixelData); 96 const PixelData* const startAddr = getAddr(startX, startY); 97 for (int destY = startY + 1; destY < endY; ++destY) 98 memcpy(getAddr(startX, destY), startAddr, rowBytes); 99 } 100 101 // Allocates space for the pixel data. Must be called before any pixels 102 // are written. Must only be called once. Returns whether allocation 103 // succeeded. 104 bool setSize(int newWidth, int newHeight); 105 106 // Returns a caller-owned pointer to the underlying native image data. 107 // (Actual use: This pointer will be owned by BitmapImage and freed in 108 // FrameData::clear()). 109 PassNativeImagePtr asNewNativeImage() const; 110 111 bool hasAlpha() const; 112 const IntRect& originalFrameRect() const { return m_originalFrameRect; } 113 FrameStatus status() const { return m_status; } 114 unsigned duration() const { return m_duration; } 115 FrameDisposalMethod disposalMethod() const { return m_disposalMethod; } 116 bool premultiplyAlpha() const { return m_premultiplyAlpha; } 117 118 void setHasAlpha(bool alpha); 119 void setColorProfile(const ColorProfile&); 120 void setOriginalFrameRect(const IntRect& r) { m_originalFrameRect = r; } 121 void setStatus(FrameStatus status); 122 void setDuration(unsigned duration) { m_duration = duration; } 123 void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; } 124 void setPremultiplyAlpha(bool premultiplyAlpha) { m_premultiplyAlpha = premultiplyAlpha; } 125 126 inline void setRGBA(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a) 127 { 128 setRGBA(getAddr(x, y), r, g, b, a); 129 } 130 131 inline PixelData* getAddr(int x, int y) 132 { 133 return m_bytes + (y * width()) + x; 134 } 135 136 // Use fix point multiplier instead of integer division or floating point math. 137 // This multipler produces exactly the same result for all values in range 0 - 255. 138 static const unsigned fixPointShift = 24; 139 static const unsigned fixPointMult = static_cast<unsigned>(1.0 / 255.0 * (1 << fixPointShift)) + 1; 140 // Multiplies unsigned value by fixpoint value and converts back to unsigned. 141 static unsigned fixPointUnsignedMultiply(unsigned fixed, unsigned v) 142 { 143 return (fixed * v) >> fixPointShift; 144 } 145 146 inline void setRGBA(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a) 147 { 148 if (m_premultiplyAlpha && a < 255) { 149 if (!a) { 150 *dest = 0; 151 return; 152 } 153 154 unsigned alphaMult = a * fixPointMult; 155 r = fixPointUnsignedMultiply(r, alphaMult); 156 g = fixPointUnsignedMultiply(g, alphaMult); 157 b = fixPointUnsignedMultiply(b, alphaMult); 158 } 159 *dest = (a << 24 | r << 16 | g << 8 | b); 160 } 161 162 private: 163 int width() const 164 { 165 return m_size.width(); 166 } 167 168 int height() const 169 { 170 return m_size.height(); 171 } 172 173 Vector<PixelData> m_backingStore; 174 PixelData* m_bytes; // The memory is backed by m_backingStore. 175 IntSize m_size; 176 // FIXME: Do we need m_colorProfile anymore? 177 ColorProfile m_colorProfile; 178 bool m_hasAlpha; 179 IntRect m_originalFrameRect; // This will always just be the entire 180 // buffer except for GIF frames whose 181 // original rect was smaller than the 182 // overall image size. 183 FrameStatus m_status; 184 unsigned m_duration; 185 FrameDisposalMethod m_disposalMethod; 186 bool m_premultiplyAlpha; 187 }; 188 189 // ImageDecoder is a base for all format-specific decoders 190 // (e.g. JPEGImageDecoder). This base manages the ImageFrame cache. 191 // 192 // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) allows image decoders to downsample 193 // at decode time. Image decoders will downsample any images larger than 194 // |m_maxNumPixels|. FIXME: Not yet supported by all decoders. 195 class ImageDecoder { 196 WTF_MAKE_NONCOPYABLE(ImageDecoder); WTF_MAKE_FAST_ALLOCATED; 197 public: 198 ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) 199 : m_scaled(false) 200 , m_premultiplyAlpha(alphaOption == ImageSource::AlphaPremultiplied) 201 , m_ignoreGammaAndColorProfile(gammaAndColorProfileOption == ImageSource::GammaAndColorProfileIgnored) 202 , m_sizeAvailable(false) 203 , m_maxNumPixels(-1) 204 , m_isAllDataReceived(false) 205 , m_failed(false) { } 206 207 virtual ~ImageDecoder() { } 208 209 // Returns a caller-owned decoder of the appropriate type. Returns 0 if 210 // we can't sniff a supported type from the provided data (possibly 211 // because there isn't enough data yet). 212 static ImageDecoder* create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); 213 214 virtual String filenameExtension() const = 0; 215 216 bool isAllDataReceived() const { return m_isAllDataReceived; } 217 218 virtual void setData(SharedBuffer* data, bool allDataReceived) 219 { 220 if (m_failed) 221 return; 222 m_data = data; 223 m_isAllDataReceived = allDataReceived; 224 } 225 226 // Lazily-decodes enough of the image to get the size (if possible). 227 // FIXME: Right now that has to be done by each subclass; factor the 228 // decode call out and use it here. 229 virtual bool isSizeAvailable() 230 { 231 return !m_failed && m_sizeAvailable; 232 } 233 234 virtual IntSize size() const { return m_size; } 235 236 IntSize scaledSize() const 237 { 238 return m_scaled ? IntSize(m_scaledColumns.size(), m_scaledRows.size()) : size(); 239 } 240 241 // This will only differ from size() for ICO (where each frame is a 242 // different icon) or other formats where different frames are different 243 // sizes. This does NOT differ from size() for GIF, since decoding GIFs 244 // composites any smaller frames against previous frames to create full- 245 // size frames. 246 virtual IntSize frameSizeAtIndex(size_t) const 247 { 248 return size(); 249 } 250 251 // Returns whether the size is legal (i.e. not going to result in 252 // overflow elsewhere). If not, marks decoding as failed. 253 virtual bool setSize(unsigned width, unsigned height) 254 { 255 if (isOverSize(width, height)) 256 return setFailed(); 257 m_size = IntSize(width, height); 258 m_sizeAvailable = true; 259 return true; 260 } 261 262 // Lazily-decodes enough of the image to get the frame count (if 263 // possible), without decoding the individual frames. 264 // FIXME: Right now that has to be done by each subclass; factor the 265 // decode call out and use it here. 266 virtual size_t frameCount() { return 1; } 267 268 virtual int repetitionCount() const { return cAnimationNone; } 269 270 // Decodes as much of the requested frame as possible, and returns an 271 // ImageDecoder-owned pointer. 272 virtual ImageFrame* frameBufferAtIndex(size_t) = 0; 273 274 // Make the best effort guess to check if the requested frame has alpha channel. 275 virtual bool frameHasAlphaAtIndex(size_t) const; 276 277 // Number of bytes in the decoded frame requested. Return 0 if not yet decoded. 278 virtual unsigned frameBytesAtIndex(size_t) const; 279 280 void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; } 281 bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorProfile; } 282 283 ImageOrientation orientation() const { return m_orientation; } 284 285 enum { iccColorProfileHeaderLength = 128 }; 286 287 static bool rgbColorProfile(const char* profileData, unsigned profileLength) 288 { 289 ASSERT_UNUSED(profileLength, profileLength >= iccColorProfileHeaderLength); 290 291 return !memcmp(&profileData[16], "RGB ", 4); 292 } 293 294 static bool inputDeviceColorProfile(const char* profileData, unsigned profileLength) 295 { 296 ASSERT_UNUSED(profileLength, profileLength >= iccColorProfileHeaderLength); 297 298 return !memcmp(&profileData[12], "mntr", 4) || !memcmp(&profileData[12], "scnr", 4); 299 } 300 301#if USE(QCMSLIB) 302 static qcms_profile* qcmsOutputDeviceProfile() 303 { 304 static qcms_profile* outputDeviceProfile = 0; 305 306 static bool qcmsInitialized = false; 307 if (!qcmsInitialized) { 308 qcmsInitialized = true; 309 // FIXME: Add optional ICCv4 support. 310#if OS(DARWIN) 311 RetainPtr<CGColorSpaceRef> monitorColorSpace = adoptCF(CGDisplayCopyColorSpace(CGMainDisplayID())); 312 CFDataRef iccProfile(CGColorSpaceCopyICCProfile(monitorColorSpace.get())); 313 if (iccProfile) { 314 size_t length = CFDataGetLength(iccProfile); 315 const unsigned char* systemProfile = CFDataGetBytePtr(iccProfile); 316 outputDeviceProfile = qcms_profile_from_memory(systemProfile, length); 317 } 318#else 319 // FIXME: add support for multiple monitors. 320 ColorProfile profile; 321 screenColorProfile(profile); 322 if (!profile.isEmpty()) 323 outputDeviceProfile = qcms_profile_from_memory(profile.data(), profile.size()); 324#endif 325 if (outputDeviceProfile && qcms_profile_is_bogus(outputDeviceProfile)) { 326 qcms_profile_release(outputDeviceProfile); 327 outputDeviceProfile = 0; 328 } 329 if (!outputDeviceProfile) 330 outputDeviceProfile = qcms_profile_sRGB(); 331 if (outputDeviceProfile) 332 qcms_profile_precache_output_transform(outputDeviceProfile); 333 } 334 return outputDeviceProfile; 335 } 336#endif 337 338 // Sets the "decode failure" flag. For caller convenience (since so 339 // many callers want to return false after calling this), returns false 340 // to enable easy tailcalling. Subclasses may override this to also 341 // clean up any local data. 342 virtual bool setFailed() 343 { 344 m_failed = true; 345 return false; 346 } 347 348 bool failed() const { return m_failed; } 349 350 // Clears decoded pixel data from before the provided frame unless that 351 // data may be needed to decode future frames (e.g. due to GIF frame 352 // compositing). 353 virtual void clearFrameBufferCache(size_t) { } 354 355#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) 356 void setMaxNumPixels(int m) { m_maxNumPixels = m; } 357#endif 358 359 // If the image has a cursor hot-spot, stores it in the argument 360 // and returns true. Otherwise returns false. 361 virtual bool hotSpot(IntPoint&) const { return false; } 362 363 protected: 364 void prepareScaleDataIfNecessary(); 365 int upperBoundScaledX(int origX, int searchStart = 0); 366 int lowerBoundScaledX(int origX, int searchStart = 0); 367 int upperBoundScaledY(int origY, int searchStart = 0); 368 int lowerBoundScaledY(int origY, int searchStart = 0); 369 int scaledY(int origY, int searchStart = 0); 370 371 RefPtr<SharedBuffer> m_data; // The encoded data. 372 Vector<ImageFrame, 1> m_frameBufferCache; 373 // FIXME: Do we need m_colorProfile any more, for any port? 374 ColorProfile m_colorProfile; 375 bool m_scaled; 376 Vector<int> m_scaledColumns; 377 Vector<int> m_scaledRows; 378 bool m_premultiplyAlpha; 379 bool m_ignoreGammaAndColorProfile; 380 ImageOrientation m_orientation; 381 382 private: 383 // Some code paths compute the size of the image as "width * height * 4" 384 // and return it as a (signed) int. Avoid overflow. 385 static bool isOverSize(unsigned width, unsigned height) 386 { 387 unsigned long long total_size = static_cast<unsigned long long>(width) 388 * static_cast<unsigned long long>(height); 389 return total_size > ((1 << 29) - 1); 390 } 391 392 IntSize m_size; 393 bool m_sizeAvailable; 394 int m_maxNumPixels; 395 bool m_isAllDataReceived; 396 bool m_failed; 397 }; 398 399} // namespace WebCore 400 401#endif 402