Index: Source/platform/image-decoders/ImageDecoder.h |
diff --git a/Source/platform/image-decoders/ImageDecoder.h b/Source/platform/image-decoders/ImageDecoder.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2ba18ae2cc92732148689a4add6e4f3ad3662b8a |
--- /dev/null |
+++ b/Source/platform/image-decoders/ImageDecoder.h |
@@ -0,0 +1,295 @@ |
+/* |
+ * 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 <ApplicationServices/ApplicationServices.h> |
+#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<ImageDecoder> create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); |
+ |
+ // Returns a decoder with custom maxDecodedSize. |
+ static PassOwnPtr<ImageDecoder> 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<CGColorSpaceRef> 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<SharedBuffer> m_data; // The encoded data. |
+ Vector<ImageFrame, 1> 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<unsigned long long>(width) |
+ * static_cast<unsigned long long>(height); |
+ return total_size > ((1 << 29) - 1); |
+ } |
+ |
+ IntSize m_size; |
+ bool m_sizeAvailable; |
+ bool m_isAllDataReceived; |
+ bool m_failed; |
+}; |
+ |
+} // namespace WebCore |
+ |
+#endif |