/* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ImageDecoder_h #define ImageDecoder_h #include "SkColorPriv.h" #include "platform/PlatformExport.h" #include "platform/PlatformScreen.h" #include "platform/SharedBuffer.h" #include "platform/graphics/ImageSource.h" #include "platform/image-decoders/ImageFrame.h" #include "public/platform/Platform.h" #include "wtf/Assertions.h" #include "wtf/RefPtr.h" #include "wtf/text/WTFString.h" #include "wtf/Vector.h" #if USE(QCMSLIB) #include "qcms.h" #if OS(MACOSX) #include #include "platform/graphics/cg/GraphicsContextCG.h" #include "wtf/RetainPtr.h" #endif #endif namespace WebCore { // ImageDecoder is a base for all format-specific decoders // (e.g. JPEGImageDecoder). This base manages the ImageFrame cache. // class PLATFORM_EXPORT ImageDecoder { WTF_MAKE_NONCOPYABLE(ImageDecoder); WTF_MAKE_FAST_ALLOCATED; public: static const size_t noDecodedImageByteLimit = blink::Platform::noDecodedImageByteLimit; ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption, size_t maxDecodedBytes) : m_premultiplyAlpha(alphaOption == ImageSource::AlphaPremultiplied) , m_ignoreGammaAndColorProfile(gammaAndColorProfileOption == ImageSource::GammaAndColorProfileIgnored) , m_maxDecodedBytes(maxDecodedBytes) , m_sizeAvailable(false) , m_isAllDataReceived(false) , m_failed(false) { } virtual ~ImageDecoder() { } // Returns a caller-owned decoder of the appropriate type. Returns 0 if // we can't sniff a supported type from the provided data (possibly // because there isn't enough data yet). // Sets m_maxDecodedBytes to Platform::maxImageDecodedBytes(). static PassOwnPtr create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); // Returns a decoder with custom maxDecodedSize. static PassOwnPtr create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption, size_t maxDecodedSize); virtual String filenameExtension() const = 0; bool isAllDataReceived() const { return m_isAllDataReceived; } virtual void setData(SharedBuffer* data, bool allDataReceived) { if (m_failed) return; m_data = data; m_isAllDataReceived = allDataReceived; } // Lazily-decodes enough of the image to get the size (if possible). // FIXME: Right now that has to be done by each subclass; factor the // decode call out and use it here. virtual bool isSizeAvailable() { return !m_failed && m_sizeAvailable; } virtual IntSize size() const { return m_size; } // Decoders which downsample images should override this method to // return the actual decoded size. virtual IntSize decodedSize() const { return size(); } // This will only differ from size() for ICO (where each frame is a // different icon) or other formats where different frames are different // sizes. This does NOT differ from size() for GIF or WebP, since // decoding GIF or WebP composites any smaller frames against previous // frames to create full-size frames. virtual IntSize frameSizeAtIndex(size_t) const { return size(); } // Returns whether the size is legal (i.e. not going to result in // overflow elsewhere). If not, marks decoding as failed. virtual bool setSize(unsigned width, unsigned height) { if (sizeCalculationMayOverflow(width, height)) return setFailed(); m_size = IntSize(width, height); m_sizeAvailable = true; return true; } // Lazily-decodes enough of the image to get the frame count (if // possible), without decoding the individual frames. // FIXME: Right now that has to be done by each subclass; factor the // decode call out and use it here. virtual size_t frameCount() { return 1; } virtual int repetitionCount() const { return cAnimationNone; } // Decodes as much of the requested frame as possible, and returns an // ImageDecoder-owned pointer. virtual ImageFrame* frameBufferAtIndex(size_t) = 0; // Make the best effort guess to check if the requested frame has alpha channel. virtual bool frameHasAlphaAtIndex(size_t) const; // Whether or not the frame is fully received. virtual bool frameIsCompleteAtIndex(size_t) const; // Duration for displaying a frame in seconds. This method is used by animated images only. virtual float frameDurationAtIndex(size_t) const { return 0; } // Number of bytes in the decoded frame requested. Return 0 if not yet decoded. virtual unsigned frameBytesAtIndex(size_t) const; void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; } bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorProfile; } ImageOrientation orientation() const { return m_orientation; } enum { iccColorProfileHeaderLength = 128 }; static bool rgbColorProfile(const char* profileData, unsigned profileLength) { ASSERT_UNUSED(profileLength, profileLength >= iccColorProfileHeaderLength); return !memcmp(&profileData[16], "RGB ", 4); } static bool inputDeviceColorProfile(const char* profileData, unsigned profileLength) { ASSERT_UNUSED(profileLength, profileLength >= iccColorProfileHeaderLength); return !memcmp(&profileData[12], "mntr", 4) || !memcmp(&profileData[12], "scnr", 4); } #if USE(QCMSLIB) static qcms_profile* qcmsOutputDeviceProfile() { static qcms_profile* outputDeviceProfile = 0; static bool qcmsInitialized = false; if (!qcmsInitialized) { qcmsInitialized = true; // FIXME: Add optional ICCv4 support. #if OS(MACOSX) RetainPtr monitorColorSpace(AdoptCF, CGDisplayCopyColorSpace(CGMainDisplayID())); CFDataRef iccProfile(CGColorSpaceCopyICCProfile(monitorColorSpace.get())); if (iccProfile) { size_t length = CFDataGetLength(iccProfile); const unsigned char* systemProfile = CFDataGetBytePtr(iccProfile); outputDeviceProfile = qcms_profile_from_memory(systemProfile, length); } #else // FIXME: add support for multiple monitors. ColorProfile profile; screenColorProfile(profile); if (!profile.isEmpty()) outputDeviceProfile = qcms_profile_from_memory(profile.data(), profile.size()); #endif if (outputDeviceProfile && qcms_profile_is_bogus(outputDeviceProfile)) { qcms_profile_release(outputDeviceProfile); outputDeviceProfile = 0; } if (!outputDeviceProfile) outputDeviceProfile = qcms_profile_sRGB(); if (outputDeviceProfile) qcms_profile_precache_output_transform(outputDeviceProfile); } return outputDeviceProfile; } #endif // Sets the "decode failure" flag. For caller convenience (since so // many callers want to return false after calling this), returns false // to enable easy tailcalling. Subclasses may override this to also // clean up any local data. virtual bool setFailed() { m_failed = true; return false; } bool failed() const { return m_failed; } // Clears decoded pixel data from all frames except the provided frame. // Callers may pass WTF::kNotFound to clear all frames. // Note: If |m_frameBufferCache| contains only one frame, it won't be cleared. // Returns the number of bytes of frame data actually cleared. virtual size_t clearCacheExceptFrame(size_t); // If the image has a cursor hot-spot, stores it in the argument // and returns true. Otherwise returns false. virtual bool hotSpot(IntPoint&) const { return false; } virtual void setMemoryAllocator(SkBitmap::Allocator* allocator) { // FIXME: this doesn't work for images with multiple frames. if (m_frameBufferCache.isEmpty()) { m_frameBufferCache.resize(1); m_frameBufferCache[0].setRequiredPreviousFrameIndex( findRequiredPreviousFrame(0, false)); } m_frameBufferCache[0].setMemoryAllocator(allocator); } protected: // Calculates the most recent frame whose image data may be needed in // order to decode frame |frameIndex|, based on frame disposal methods // and |frameRectIsOpaque|, where |frameRectIsOpaque| signifies whether // the rectangle of frame at |frameIndex| is known to be opaque. // If no previous frame's data is required, returns WTF::kNotFound. // // This function requires that the previous frame's // |m_requiredPreviousFrameIndex| member has been set correctly. The // easiest way to ensure this is for subclasses to call this method and // store the result on the frame via setRequiredPreviousFrameIndex() // as soon as the frame has been created and parsed sufficiently to // determine the disposal method; assuming this happens for all frames // in order, the required invariant will hold. // // Image formats which do not use more than one frame do not need to // worry about this; see comments on // ImageFrame::m_requiredPreviousFrameIndex. size_t findRequiredPreviousFrame(size_t frameIndex, bool frameRectIsOpaque); virtual void clearFrameBuffer(size_t frameIndex); RefPtr m_data; // The encoded data. Vector m_frameBufferCache; bool m_premultiplyAlpha; bool m_ignoreGammaAndColorProfile; ImageOrientation m_orientation; // The maximum amount of memory a decoded image should require. Ideally, // image decoders should downsample large images to fit under this limit // (and then return the downsampled size from decodedSize()). Ignoring // this limit can cause excessive memory use or even crashes on low- // memory devices. size_t m_maxDecodedBytes; private: // Some code paths compute the size of the image as "width * height * 4" // and return it as a (signed) int. Avoid overflow. static bool sizeCalculationMayOverflow(unsigned width, unsigned height) { unsigned long long total_size = static_cast(width) * static_cast(height); return total_size > ((1 << 29) - 1); } IntSize m_size; bool m_sizeAvailable; bool m_isAllDataReceived; bool m_failed; }; } // namespace WebCore #endif