• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #ifndef ImageDecoder_h
28 #define ImageDecoder_h
29 
30 #include "SkColorPriv.h"
31 #include "platform/PlatformExport.h"
32 #include "platform/PlatformScreen.h"
33 #include "platform/SharedBuffer.h"
34 #include "platform/graphics/ImageSource.h"
35 #include "platform/image-decoders/ImageFrame.h"
36 #include "public/platform/Platform.h"
37 #include "wtf/Assertions.h"
38 #include "wtf/RefPtr.h"
39 #include "wtf/text/WTFString.h"
40 #include "wtf/Vector.h"
41 
42 #if USE(QCMSLIB)
43 #include "qcms.h"
44 #if OS(MACOSX)
45 #include <ApplicationServices/ApplicationServices.h>
46 #include "wtf/RetainPtr.h"
47 #endif
48 #endif
49 
50 namespace WebCore {
51 
52 // ImageDecoder is a base for all format-specific decoders
53 // (e.g. JPEGImageDecoder). This base manages the ImageFrame cache.
54 //
55 class PLATFORM_EXPORT ImageDecoder {
56     WTF_MAKE_NONCOPYABLE(ImageDecoder); WTF_MAKE_FAST_ALLOCATED;
57 public:
58     static const size_t noDecodedImageByteLimit = blink::Platform::noDecodedImageByteLimit;
59 
ImageDecoder(ImageSource::AlphaOption alphaOption,ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption,size_t maxDecodedBytes)60     ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption, size_t maxDecodedBytes)
61         : m_premultiplyAlpha(alphaOption == ImageSource::AlphaPremultiplied)
62         , m_ignoreGammaAndColorProfile(gammaAndColorProfileOption == ImageSource::GammaAndColorProfileIgnored)
63         , m_maxDecodedBytes(maxDecodedBytes)
64         , m_sizeAvailable(false)
65         , m_isAllDataReceived(false)
66         , m_failed(false) { }
67 
~ImageDecoder()68     virtual ~ImageDecoder() { }
69 
70     // Returns a caller-owned decoder of the appropriate type.  Returns 0 if
71     // we can't sniff a supported type from the provided data (possibly
72     // because there isn't enough data yet).
73     // Sets m_maxDecodedBytes to Platform::maxImageDecodedBytes().
74     static PassOwnPtr<ImageDecoder> create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption);
75 
76     // Returns a decoder with custom maxDecodedSize.
77     static PassOwnPtr<ImageDecoder> create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption, size_t maxDecodedSize);
78 
79     virtual String filenameExtension() const = 0;
80 
isAllDataReceived()81     bool isAllDataReceived() const { return m_isAllDataReceived; }
82 
setData(SharedBuffer * data,bool allDataReceived)83     virtual void setData(SharedBuffer* data, bool allDataReceived)
84     {
85         if (m_failed)
86             return;
87         m_data = data;
88         m_isAllDataReceived = allDataReceived;
89     }
90 
91     // Lazily-decodes enough of the image to get the size (if possible).
92     // FIXME: Right now that has to be done by each subclass; factor the
93     // decode call out and use it here.
isSizeAvailable()94     virtual bool isSizeAvailable()
95     {
96         return !m_failed && m_sizeAvailable;
97     }
98 
size()99     virtual IntSize size() const { return m_size; }
100 
101     // Decoders which downsample images should override this method to
102     // return the actual decoded size.
decodedSize()103     virtual IntSize decodedSize() const { return size(); }
104 
105     // This will only differ from size() for ICO (where each frame is a
106     // different icon) or other formats where different frames are different
107     // sizes. This does NOT differ from size() for GIF or WebP, since
108     // decoding GIF or WebP composites any smaller frames against previous
109     // frames to create full-size frames.
frameSizeAtIndex(size_t)110     virtual IntSize frameSizeAtIndex(size_t) const
111     {
112         return size();
113     }
114 
115     // Returns whether the size is legal (i.e. not going to result in
116     // overflow elsewhere).  If not, marks decoding as failed.
setSize(unsigned width,unsigned height)117     virtual bool setSize(unsigned width, unsigned height)
118     {
119         if (sizeCalculationMayOverflow(width, height))
120             return setFailed();
121         m_size = IntSize(width, height);
122         m_sizeAvailable = true;
123         return true;
124     }
125 
126     // Lazily-decodes enough of the image to get the frame count (if
127     // possible), without decoding the individual frames.
128     // FIXME: Right now that has to be done by each subclass; factor the
129     // decode call out and use it here.
frameCount()130     virtual size_t frameCount() { return 1; }
131 
repetitionCount()132     virtual int repetitionCount() const { return cAnimationNone; }
133 
134     // Decodes as much of the requested frame as possible, and returns an
135     // ImageDecoder-owned pointer.
136     virtual ImageFrame* frameBufferAtIndex(size_t) = 0;
137 
138     // Make the best effort guess to check if the requested frame has alpha channel.
139     virtual bool frameHasAlphaAtIndex(size_t) const;
140 
141     // Whether or not the frame is fully received.
142     virtual bool frameIsCompleteAtIndex(size_t) const;
143 
144     // Duration for displaying a frame in seconds. This method is used by animated images only.
frameDurationAtIndex(size_t)145     virtual float frameDurationAtIndex(size_t) const { return 0; }
146 
147     // Number of bytes in the decoded frame requested. Return 0 if not yet decoded.
148     virtual unsigned frameBytesAtIndex(size_t) const;
149 
orientation()150     ImageOrientation orientation() const { return m_orientation; }
151 
152     static bool deferredImageDecodingEnabled();
153 
setIgnoreGammaAndColorProfile(bool flag)154     void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; }
ignoresGammaAndColorProfile()155     bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorProfile; }
156 
hasColorProfile()157     virtual bool hasColorProfile() const { return false; }
158 
159 #if USE(QCMSLIB)
160     enum { iccColorProfileHeaderLength = 128 };
161 
rgbColorProfile(const char * profileData,unsigned profileLength)162     static bool rgbColorProfile(const char* profileData, unsigned profileLength)
163     {
164         ASSERT_UNUSED(profileLength, profileLength >= iccColorProfileHeaderLength);
165 
166         return !memcmp(&profileData[16], "RGB ", 4);
167     }
168 
inputDeviceColorProfile(const char * profileData,unsigned profileLength)169     static bool inputDeviceColorProfile(const char* profileData, unsigned profileLength)
170     {
171         ASSERT_UNUSED(profileLength, profileLength >= iccColorProfileHeaderLength);
172 
173         return !memcmp(&profileData[12], "mntr", 4) || !memcmp(&profileData[12], "scnr", 4);
174     }
175 
176     class OutputDeviceProfile {
177     public:
OutputDeviceProfile()178         OutputDeviceProfile()
179             : m_outputDeviceProfile(0)
180         {
181             // FIXME: Add optional ICCv4 support.
182 #if OS(MACOSX)
183             RetainPtr<CGColorSpaceRef> monitorColorSpace(AdoptCF, CGDisplayCopyColorSpace(CGMainDisplayID()));
184             CFDataRef iccProfile(CGColorSpaceCopyICCProfile(monitorColorSpace.get()));
185             if (iccProfile) {
186                 size_t length = CFDataGetLength(iccProfile);
187                 const unsigned char* systemProfile = CFDataGetBytePtr(iccProfile);
188                 m_outputDeviceProfile = qcms_profile_from_memory(systemProfile, length);
189             }
190 #else
191             // FIXME: add support for multiple monitors.
192             ColorProfile profile;
193             screenColorProfile(profile);
194             if (!profile.isEmpty())
195                 m_outputDeviceProfile = qcms_profile_from_memory(profile.data(), profile.size());
196 #endif
197             if (m_outputDeviceProfile && qcms_profile_is_bogus(m_outputDeviceProfile)) {
198                 qcms_profile_release(m_outputDeviceProfile);
199                 m_outputDeviceProfile = 0;
200             }
201             if (!m_outputDeviceProfile)
202                 m_outputDeviceProfile = qcms_profile_sRGB();
203             if (m_outputDeviceProfile)
204                 qcms_profile_precache_output_transform(m_outputDeviceProfile);
205         }
206 
profile()207         qcms_profile* profile() const { return m_outputDeviceProfile; }
208 
209     private:
210         qcms_profile* m_outputDeviceProfile;
211     };
212 
qcmsOutputDeviceProfile()213     static qcms_profile* qcmsOutputDeviceProfile()
214     {
215         AtomicallyInitializedStatic(OutputDeviceProfile*, outputDeviceProfile = new OutputDeviceProfile());
216 
217         return outputDeviceProfile->profile();
218     }
219 #endif
220 
221     // Sets the "decode failure" flag.  For caller convenience (since so
222     // many callers want to return false after calling this), returns false
223     // to enable easy tailcalling.  Subclasses may override this to also
224     // clean up any local data.
setFailed()225     virtual bool setFailed()
226     {
227         m_failed = true;
228         return false;
229     }
230 
failed()231     bool failed() const { return m_failed; }
232 
233     // Clears decoded pixel data from all frames except the provided frame.
234     // Callers may pass WTF::kNotFound to clear all frames.
235     // Note: If |m_frameBufferCache| contains only one frame, it won't be cleared.
236     // Returns the number of bytes of frame data actually cleared.
237     virtual size_t clearCacheExceptFrame(size_t);
238 
239     // If the image has a cursor hot-spot, stores it in the argument
240     // and returns true. Otherwise returns false.
hotSpot(IntPoint &)241     virtual bool hotSpot(IntPoint&) const { return false; }
242 
setMemoryAllocator(SkBitmap::Allocator * allocator)243     virtual void setMemoryAllocator(SkBitmap::Allocator* allocator)
244     {
245         // FIXME: this doesn't work for images with multiple frames.
246         if (m_frameBufferCache.isEmpty()) {
247             m_frameBufferCache.resize(1);
248             m_frameBufferCache[0].setRequiredPreviousFrameIndex(
249                 findRequiredPreviousFrame(0, false));
250         }
251         m_frameBufferCache[0].setMemoryAllocator(allocator);
252     }
253 
254 protected:
255     // Calculates the most recent frame whose image data may be needed in
256     // order to decode frame |frameIndex|, based on frame disposal methods
257     // and |frameRectIsOpaque|, where |frameRectIsOpaque| signifies whether
258     // the rectangle of frame at |frameIndex| is known to be opaque.
259     // If no previous frame's data is required, returns WTF::kNotFound.
260     //
261     // This function requires that the previous frame's
262     // |m_requiredPreviousFrameIndex| member has been set correctly. The
263     // easiest way to ensure this is for subclasses to call this method and
264     // store the result on the frame via setRequiredPreviousFrameIndex()
265     // as soon as the frame has been created and parsed sufficiently to
266     // determine the disposal method; assuming this happens for all frames
267     // in order, the required invariant will hold.
268     //
269     // Image formats which do not use more than one frame do not need to
270     // worry about this; see comments on
271     // ImageFrame::m_requiredPreviousFrameIndex.
272     size_t findRequiredPreviousFrame(size_t frameIndex, bool frameRectIsOpaque);
273 
274     virtual void clearFrameBuffer(size_t frameIndex);
275 
276     RefPtr<SharedBuffer> m_data; // The encoded data.
277     Vector<ImageFrame, 1> m_frameBufferCache;
278     bool m_premultiplyAlpha;
279     bool m_ignoreGammaAndColorProfile;
280     ImageOrientation m_orientation;
281 
282     // The maximum amount of memory a decoded image should require. Ideally,
283     // image decoders should downsample large images to fit under this limit
284     // (and then return the downsampled size from decodedSize()). Ignoring
285     // this limit can cause excessive memory use or even crashes on low-
286     // memory devices.
287     size_t m_maxDecodedBytes;
288 
289 private:
290     // Some code paths compute the size of the image as "width * height * 4"
291     // and return it as a (signed) int.  Avoid overflow.
sizeCalculationMayOverflow(unsigned width,unsigned height)292     static bool sizeCalculationMayOverflow(unsigned width, unsigned height)
293     {
294         unsigned long long total_size = static_cast<unsigned long long>(width)
295                                       * static_cast<unsigned long long>(height);
296         return total_size > ((1 << 29) - 1);
297     }
298 
299     IntSize m_size;
300     bool m_sizeAvailable;
301     bool m_isAllDataReceived;
302     bool m_failed;
303 };
304 
305 } // namespace WebCore
306 
307 #endif
308