| /* | 
 |  * 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 SKY_ENGINE_PLATFORM_IMAGE_DECODERS_IMAGEDECODER_H_ | 
 | #define SKY_ENGINE_PLATFORM_IMAGE_DECODERS_IMAGEDECODER_H_ | 
 |  | 
 | #include "platform/image-decoders/ImageFrame.h" | 
 | #include "sky/engine/platform/PlatformExport.h" | 
 | #include "sky/engine/platform/PlatformScreen.h" | 
 | #include "sky/engine/platform/SharedBuffer.h" | 
 | #include "sky/engine/platform/graphics/ImageSource.h" | 
 | #include "sky/engine/public/platform/Platform.h" | 
 | #include "sky/engine/wtf/Assertions.h" | 
 | #include "sky/engine/wtf/PassOwnPtr.h" | 
 | #include "sky/engine/wtf/RefPtr.h" | 
 | #include "sky/engine/wtf/Threading.h" | 
 | #include "sky/engine/wtf/Vector.h" | 
 | #include "sky/engine/wtf/text/WTFString.h" | 
 | #include "third_party/skia/include/core/SkColorPriv.h" | 
 |  | 
 | #if USE(QCMSLIB) | 
 | #include "qcms.h" | 
 | #endif | 
 |  | 
 | namespace blink { | 
 |  | 
 | // ImagePlanes can be used to decode color components into provided buffers instead of using an ImageFrame. | 
 | class PLATFORM_EXPORT ImagePlanes { | 
 | public: | 
 |     ImagePlanes(); | 
 |     ImagePlanes(void* planes[3], size_t rowBytes[3]); | 
 |  | 
 |     void* plane(int); | 
 |     size_t rowBytes(int) const; | 
 |  | 
 | private: | 
 |     void* m_planes[3]; | 
 |     size_t m_rowBytes[3]; | 
 | }; | 
 |  | 
 | // 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; | 
 |     } | 
 |  | 
 |     virtual bool isSizeAvailable() | 
 |     { | 
 |         return !m_failed && m_sizeAvailable; | 
 |     } | 
 |  | 
 |     bool isSizeAvailable() const | 
 |     { | 
 |         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(); } | 
 |  | 
 |     // Decoders which support YUV decoding can override this to | 
 |     // give potentially different sizes per component. | 
 |     virtual IntSize decodedYUVSize(int component) const { return decodedSize(); } | 
 |  | 
 |     // 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; | 
 |  | 
 |     ImageOrientation orientation() const { return m_orientation; } | 
 |  | 
 |     static bool deferredImageDecodingEnabled(); | 
 |  | 
 |     void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; } | 
 |     bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorProfile; } | 
 |  | 
 |     virtual bool hasColorProfile() const { return false; } | 
 |  | 
 | #if USE(QCMSLIB) | 
 |     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); | 
 |     } | 
 |  | 
 |     class OutputDeviceProfile { | 
 |     public: | 
 |         OutputDeviceProfile() | 
 |             : m_outputDeviceProfile(0) | 
 |         { | 
 |             // FIXME: Add optional ICCv4 support. | 
 |             // FIXME: add support for multiple monitors. | 
 |             ColorProfile profile; | 
 |             screenColorProfile(profile); | 
 |             if (!profile.isEmpty()) | 
 |                 m_outputDeviceProfile = qcms_profile_from_memory(profile.data(), profile.size()); | 
 |             if (m_outputDeviceProfile && qcms_profile_is_bogus(m_outputDeviceProfile)) { | 
 |                 qcms_profile_release(m_outputDeviceProfile); | 
 |                 m_outputDeviceProfile = 0; | 
 |             } | 
 |             if (!m_outputDeviceProfile) | 
 |                 m_outputDeviceProfile = qcms_profile_sRGB(); | 
 |             if (m_outputDeviceProfile) | 
 |                 qcms_profile_precache_output_transform(m_outputDeviceProfile); | 
 |         } | 
 |  | 
 |         qcms_profile* profile() const { return m_outputDeviceProfile; } | 
 |  | 
 |     private: | 
 |         qcms_profile* m_outputDeviceProfile; | 
 |     }; | 
 |  | 
 |     static qcms_profile* qcmsOutputDeviceProfile() | 
 |     { | 
 |         AtomicallyInitializedStatic(OutputDeviceProfile*, outputDeviceProfile = new OutputDeviceProfile()); | 
 |  | 
 |         return outputDeviceProfile->profile(); | 
 |     } | 
 | #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); | 
 |     } | 
 |  | 
 |     virtual bool canDecodeToYUV() const { return false; } | 
 |     virtual bool decodeToYUV() { return false; } | 
 |     virtual void setImagePlanes(PassOwnPtr<ImagePlanes>) { } | 
 |  | 
 | 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 blink | 
 |  | 
 | #endif  // SKY_ENGINE_PLATFORM_IMAGE_DECODERS_IMAGEDECODER_H_ |