OLD | NEW |
| (Empty) |
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 "core/platform/graphics/ImageSource.h" | |
32 #include "core/platform/graphics/skia/NativeImageSkia.h" | |
33 #include "platform/PlatformScreen.h" | |
34 #include "platform/SharedBuffer.h" | |
35 #include "platform/geometry/IntRect.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 "core/platform/graphics/cg/GraphicsContextCG.h" | |
47 #include "wtf/RetainPtr.h" | |
48 #endif | |
49 #endif | |
50 | |
51 namespace WebCore { | |
52 | |
53 // ImageFrame represents the decoded image data. This buffer is what all | |
54 // decoders write a single frame into. | |
55 class ImageFrame { | |
56 public: | |
57 enum Status { FrameEmpty, FramePartial, FrameComplete }; | |
58 enum DisposalMethod { | |
59 // If you change the numeric values of these, make sure you audit | |
60 // all users, as some users may cast raw values to/from these | |
61 // constants. | |
62 DisposeNotSpecified, // Leave frame in framebuffer | |
63 DisposeKeep, // Leave frame in framebuffer | |
64 DisposeOverwriteBgcolor, // Clear frame to fully transparent | |
65 DisposeOverwritePrevious // Clear frame to previous framebuffer cont
ents | |
66 }; | |
67 // Indicates how non-opaque pixels in the current frame rectangle | |
68 // are blended with those in the previous frame. | |
69 // Notes: | |
70 // * GIF always uses 'BlendAtopPreviousFrame'. | |
71 // * WebP also uses the 'BlendAtopBgcolor' option. This is useful for | |
72 // cases where one wants to transform a few opaque pixels of the | |
73 // previous frame into non-opaque pixels in the current frame. | |
74 enum AlphaBlendSource { | |
75 // Blend non-opaque pixels atop the corresponding pixels in the | |
76 // initial buffer state (i.e. any previous frame buffer after having | |
77 // been properly disposed). | |
78 BlendAtopPreviousFrame, | |
79 | |
80 // Blend non-opaque pixels against fully transparent (i.e. simply | |
81 // overwrite the corresponding pixels). | |
82 BlendAtopBgcolor, | |
83 }; | |
84 typedef uint32_t PixelData; | |
85 | |
86 ImageFrame(); | |
87 | |
88 ImageFrame(const ImageFrame& other) { operator=(other); } | |
89 | |
90 // For backends which refcount their data, this operator doesn't need to | |
91 // create a new copy of the image data, only increase the ref count. | |
92 ImageFrame& operator=(const ImageFrame& other); | |
93 | |
94 // These do not touch other metadata, only the raw pixel data. | |
95 void clearPixelData(); | |
96 void zeroFillPixelData(); | |
97 void zeroFillFrameRect(const IntRect&); | |
98 | |
99 // Makes this frame have an independent copy of the provided image's | |
100 // pixel data, so that modifications in one frame are not reflected in | |
101 // the other. Returns whether the copy succeeded. | |
102 bool copyBitmapData(const ImageFrame&); | |
103 | |
104 // Copies the pixel data at [(startX, startY), (endX, startY)) to the | |
105 // same X-coordinates on each subsequent row up to but not including | |
106 // endY. | |
107 void copyRowNTimes(int startX, int endX, int startY, int endY) | |
108 { | |
109 ASSERT(startX < width()); | |
110 ASSERT(endX <= width()); | |
111 ASSERT(startY < height()); | |
112 ASSERT(endY <= height()); | |
113 const int rowBytes = (endX - startX) * sizeof(PixelData); | |
114 const PixelData* const startAddr = getAddr(startX, startY); | |
115 for (int destY = startY + 1; destY < endY; ++destY) | |
116 memcpy(getAddr(startX, destY), startAddr, rowBytes); | |
117 } | |
118 | |
119 // Allocates space for the pixel data. Must be called before any pixels | |
120 // are written. Must only be called once. Returns whether allocation | |
121 // succeeded. | |
122 bool setSize(int newWidth, int newHeight); | |
123 | |
124 // Returns a caller-owned pointer to the underlying native image data. | |
125 // (Actual use: This pointer will be owned by BitmapImage and freed in | |
126 // FrameData::clear()). | |
127 PassRefPtr<NativeImageSkia> asNewNativeImage() const; | |
128 | |
129 bool hasAlpha() const; | |
130 const IntRect& originalFrameRect() const { return m_originalFrameRect; } | |
131 Status status() const { return m_status; } | |
132 unsigned duration() const { return m_duration; } | |
133 DisposalMethod disposalMethod() const { return m_disposalMethod; } | |
134 AlphaBlendSource alphaBlendSource() const { return m_alphaBlendSource; } | |
135 bool premultiplyAlpha() const { return m_premultiplyAlpha; } | |
136 SkBitmap::Allocator* allocator() const { return m_allocator; } | |
137 const SkBitmap& getSkBitmap() const { return m_bitmap->bitmap(); } | |
138 // Returns true if the pixels changed, but the bitmap has not yet been n
otified. | |
139 bool pixelsChanged() const { return m_pixelsChanged; } | |
140 | |
141 size_t requiredPreviousFrameIndex() const | |
142 { | |
143 ASSERT(m_requiredPreviousFrameIndexValid); | |
144 return m_requiredPreviousFrameIndex; | |
145 } | |
146 #if !ASSERT_DISABLED | |
147 bool requiredPreviousFrameIndexValid() const { return m_requiredPrevious
FrameIndexValid; } | |
148 #endif | |
149 void setHasAlpha(bool alpha); | |
150 void setOriginalFrameRect(const IntRect& r) { m_originalFrameRect = r; } | |
151 void setStatus(Status); | |
152 void setDuration(unsigned duration) { m_duration = duration; } | |
153 void setDisposalMethod(DisposalMethod disposalMethod) { m_disposalMethod
= disposalMethod; } | |
154 void setAlphaBlendSource(AlphaBlendSource alphaBlendSource) { m_alphaBle
ndSource = alphaBlendSource; } | |
155 void setPremultiplyAlpha(bool premultiplyAlpha) { m_premultiplyAlpha = p
remultiplyAlpha; } | |
156 void setMemoryAllocator(SkBitmap::Allocator* allocator) { m_allocator =
allocator; } | |
157 void setSkBitmap(const SkBitmap& bitmap) { m_bitmap = NativeImageSkia::c
reate(bitmap); } | |
158 // The pixelsChanged flag needs to be set when the raw pixel data was di
rectly modified | |
159 // (e.g. through a pointer or setRGBA). The flag is usually set after a
batch of changes was made. | |
160 void setPixelsChanged(bool pixelsChanged) { m_pixelsChanged = pixelsChan
ged; } | |
161 | |
162 void setRequiredPreviousFrameIndex(size_t previousFrameIndex) | |
163 { | |
164 m_requiredPreviousFrameIndex = previousFrameIndex; | |
165 #if !ASSERT_DISABLED | |
166 m_requiredPreviousFrameIndexValid = true; | |
167 #endif | |
168 } | |
169 | |
170 inline PixelData* getAddr(int x, int y) | |
171 { | |
172 return m_bitmap->bitmap().getAddr32(x, y); | |
173 } | |
174 | |
175 inline void setRGBA(int x, int y, unsigned r, unsigned g, unsigned b, un
signed a) | |
176 { | |
177 setRGBA(getAddr(x, y), r, g, b, a); | |
178 } | |
179 | |
180 static const unsigned div255 = static_cast<unsigned>(1.0 / 255 * (1 << 2
4)) + 1; | |
181 | |
182 inline void setRGBA(PixelData* dest, unsigned r, unsigned g, unsigned b,
unsigned a) | |
183 { | |
184 if (m_premultiplyAlpha && a < 255) { | |
185 if (!a) { | |
186 *dest = 0; | |
187 return; | |
188 } | |
189 | |
190 unsigned alpha = a * div255; | |
191 r = (r * alpha) >> 24; | |
192 g = (g * alpha) >> 24; | |
193 b = (b * alpha) >> 24; | |
194 } | |
195 | |
196 // Call the "NoCheck" version since we may deliberately pass non-pre
multiplied | |
197 // values, and we don't want an assert. | |
198 *dest = SkPackARGB32NoCheck(a, r, g, b); | |
199 } | |
200 | |
201 inline void setRGBARaw(PixelData* dest, unsigned r, unsigned g, unsigned
b, unsigned a) | |
202 { | |
203 *dest = SkPackARGB32NoCheck(a, r, g, b); | |
204 } | |
205 | |
206 // Notifies the SkBitmap if any pixels changed and resets the flag. | |
207 inline void notifyBitmapIfPixelsChanged() | |
208 { | |
209 if (m_pixelsChanged) | |
210 m_bitmap->bitmap().notifyPixelsChanged(); | |
211 m_pixelsChanged = false; | |
212 } | |
213 | |
214 private: | |
215 int width() const | |
216 { | |
217 return m_bitmap->bitmap().width(); | |
218 } | |
219 | |
220 int height() const | |
221 { | |
222 return m_bitmap->bitmap().height(); | |
223 } | |
224 | |
225 RefPtr<NativeImageSkia> m_bitmap; | |
226 SkBitmap::Allocator* m_allocator; | |
227 bool m_hasAlpha; | |
228 // This will always just be the entire buffer except for GIF or WebP | |
229 // frames whose original rect was smaller than the overall image size. | |
230 IntRect m_originalFrameRect; | |
231 Status m_status; | |
232 unsigned m_duration; | |
233 DisposalMethod m_disposalMethod; | |
234 AlphaBlendSource m_alphaBlendSource; | |
235 bool m_premultiplyAlpha; | |
236 // True if the pixels changed, but the bitmap has not yet been notified. | |
237 bool m_pixelsChanged; | |
238 | |
239 // The frame that must be decoded before this frame can be decoded. | |
240 // WTF::kNotFound if this frame doesn't require any previous frame. | |
241 // This is used by ImageDecoder::clearCacheExceptFrame(), and will never | |
242 // be read for image formats that do not have multiple frames. | |
243 size_t m_requiredPreviousFrameIndex; | |
244 #if !ASSERT_DISABLED | |
245 bool m_requiredPreviousFrameIndexValid; | |
246 #endif | |
247 }; | |
248 | |
249 // ImageDecoder is a base for all format-specific decoders | |
250 // (e.g. JPEGImageDecoder). This base manages the ImageFrame cache. | |
251 // | |
252 class ImageDecoder { | |
253 WTF_MAKE_NONCOPYABLE(ImageDecoder); WTF_MAKE_FAST_ALLOCATED; | |
254 public: | |
255 static const size_t noDecodedImageByteLimit = blink::Platform::noDecoded
ImageByteLimit; | |
256 | |
257 ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAnd
ColorProfileOption gammaAndColorProfileOption, size_t maxDecodedBytes) | |
258 : m_premultiplyAlpha(alphaOption == ImageSource::AlphaPremultiplied) | |
259 , m_ignoreGammaAndColorProfile(gammaAndColorProfileOption == ImageSo
urce::GammaAndColorProfileIgnored) | |
260 , m_maxDecodedBytes(maxDecodedBytes) | |
261 , m_sizeAvailable(false) | |
262 , m_isAllDataReceived(false) | |
263 , m_failed(false) { } | |
264 | |
265 virtual ~ImageDecoder() { } | |
266 | |
267 // Returns a caller-owned decoder of the appropriate type. Returns 0 if | |
268 // we can't sniff a supported type from the provided data (possibly | |
269 // because there isn't enough data yet). | |
270 // Sets m_maxDecodedBytes to Platform::maxImageDecodedBytes(). | |
271 static PassOwnPtr<ImageDecoder> create(const SharedBuffer& data, ImageSo
urce::AlphaOption, ImageSource::GammaAndColorProfileOption); | |
272 | |
273 // Returns a decoder with custom maxDecodedSize. | |
274 static PassOwnPtr<ImageDecoder> create(const SharedBuffer& data, ImageSo
urce::AlphaOption, ImageSource::GammaAndColorProfileOption, size_t maxDecodedSiz
e); | |
275 | |
276 virtual String filenameExtension() const = 0; | |
277 | |
278 bool isAllDataReceived() const { return m_isAllDataReceived; } | |
279 | |
280 virtual void setData(SharedBuffer* data, bool allDataReceived) | |
281 { | |
282 if (m_failed) | |
283 return; | |
284 m_data = data; | |
285 m_isAllDataReceived = allDataReceived; | |
286 } | |
287 | |
288 // Lazily-decodes enough of the image to get the size (if possible). | |
289 // FIXME: Right now that has to be done by each subclass; factor the | |
290 // decode call out and use it here. | |
291 virtual bool isSizeAvailable() | |
292 { | |
293 return !m_failed && m_sizeAvailable; | |
294 } | |
295 | |
296 virtual IntSize size() const { return m_size; } | |
297 | |
298 // Decoders which downsample images should override this method to | |
299 // return the actual decoded size. | |
300 virtual IntSize decodedSize() const { return size(); } | |
301 | |
302 // This will only differ from size() for ICO (where each frame is a | |
303 // different icon) or other formats where different frames are different | |
304 // sizes. This does NOT differ from size() for GIF or WebP, since | |
305 // decoding GIF or WebP composites any smaller frames against previous | |
306 // frames to create full-size frames. | |
307 virtual IntSize frameSizeAtIndex(size_t) const | |
308 { | |
309 return size(); | |
310 } | |
311 | |
312 // Returns whether the size is legal (i.e. not going to result in | |
313 // overflow elsewhere). If not, marks decoding as failed. | |
314 virtual bool setSize(unsigned width, unsigned height) | |
315 { | |
316 if (sizeCalculationMayOverflow(width, height)) | |
317 return setFailed(); | |
318 m_size = IntSize(width, height); | |
319 m_sizeAvailable = true; | |
320 return true; | |
321 } | |
322 | |
323 // Lazily-decodes enough of the image to get the frame count (if | |
324 // possible), without decoding the individual frames. | |
325 // FIXME: Right now that has to be done by each subclass; factor the | |
326 // decode call out and use it here. | |
327 virtual size_t frameCount() { return 1; } | |
328 | |
329 virtual int repetitionCount() const { return cAnimationNone; } | |
330 | |
331 // Decodes as much of the requested frame as possible, and returns an | |
332 // ImageDecoder-owned pointer. | |
333 virtual ImageFrame* frameBufferAtIndex(size_t) = 0; | |
334 | |
335 // Make the best effort guess to check if the requested frame has alpha
channel. | |
336 virtual bool frameHasAlphaAtIndex(size_t) const; | |
337 | |
338 // Whether or not the frame is fully received. | |
339 virtual bool frameIsCompleteAtIndex(size_t) const; | |
340 | |
341 // Duration for displaying a frame in seconds. This method is used by an
imated images only. | |
342 virtual float frameDurationAtIndex(size_t) const { return 0; } | |
343 | |
344 // Number of bytes in the decoded frame requested. Return 0 if not yet d
ecoded. | |
345 virtual unsigned frameBytesAtIndex(size_t) const; | |
346 | |
347 void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorPro
file = flag; } | |
348 bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorP
rofile; } | |
349 | |
350 ImageOrientation orientation() const { return m_orientation; } | |
351 | |
352 enum { iccColorProfileHeaderLength = 128 }; | |
353 | |
354 static bool rgbColorProfile(const char* profileData, unsigned profileLen
gth) | |
355 { | |
356 ASSERT_UNUSED(profileLength, profileLength >= iccColorProfileHeaderL
ength); | |
357 | |
358 return !memcmp(&profileData[16], "RGB ", 4); | |
359 } | |
360 | |
361 static bool inputDeviceColorProfile(const char* profileData, unsigned pr
ofileLength) | |
362 { | |
363 ASSERT_UNUSED(profileLength, profileLength >= iccColorProfileHeaderL
ength); | |
364 | |
365 return !memcmp(&profileData[12], "mntr", 4) || !memcmp(&profileData[
12], "scnr", 4); | |
366 } | |
367 | |
368 #if USE(QCMSLIB) | |
369 static qcms_profile* qcmsOutputDeviceProfile() | |
370 { | |
371 static qcms_profile* outputDeviceProfile = 0; | |
372 | |
373 static bool qcmsInitialized = false; | |
374 if (!qcmsInitialized) { | |
375 qcmsInitialized = true; | |
376 // FIXME: Add optional ICCv4 support. | |
377 #if OS(MACOSX) | |
378 RetainPtr<CGColorSpaceRef> monitorColorSpace(AdoptCF, CGDisplayC
opyColorSpace(CGMainDisplayID())); | |
379 CFDataRef iccProfile(CGColorSpaceCopyICCProfile(monitorColorSpac
e.get())); | |
380 if (iccProfile) { | |
381 size_t length = CFDataGetLength(iccProfile); | |
382 const unsigned char* systemProfile = CFDataGetBytePtr(iccPro
file); | |
383 outputDeviceProfile = qcms_profile_from_memory(systemProfile
, length); | |
384 } | |
385 #else | |
386 // FIXME: add support for multiple monitors. | |
387 ColorProfile profile; | |
388 screenColorProfile(profile); | |
389 if (!profile.isEmpty()) | |
390 outputDeviceProfile = qcms_profile_from_memory(profile.data(
), profile.size()); | |
391 #endif | |
392 if (outputDeviceProfile && qcms_profile_is_bogus(outputDevicePro
file)) { | |
393 qcms_profile_release(outputDeviceProfile); | |
394 outputDeviceProfile = 0; | |
395 } | |
396 if (!outputDeviceProfile) | |
397 outputDeviceProfile = qcms_profile_sRGB(); | |
398 if (outputDeviceProfile) | |
399 qcms_profile_precache_output_transform(outputDeviceProfile); | |
400 } | |
401 return outputDeviceProfile; | |
402 } | |
403 #endif | |
404 | |
405 // Sets the "decode failure" flag. For caller convenience (since so | |
406 // many callers want to return false after calling this), returns false | |
407 // to enable easy tailcalling. Subclasses may override this to also | |
408 // clean up any local data. | |
409 virtual bool setFailed() | |
410 { | |
411 m_failed = true; | |
412 return false; | |
413 } | |
414 | |
415 bool failed() const { return m_failed; } | |
416 | |
417 // Clears decoded pixel data from all frames except the provided frame. | |
418 // Callers may pass WTF::kNotFound to clear all frames. | |
419 // Note: If |m_frameBufferCache| contains only one frame, it won't be cl
eared. | |
420 // Returns the number of bytes of frame data actually cleared. | |
421 virtual size_t clearCacheExceptFrame(size_t); | |
422 | |
423 // If the image has a cursor hot-spot, stores it in the argument | |
424 // and returns true. Otherwise returns false. | |
425 virtual bool hotSpot(IntPoint&) const { return false; } | |
426 | |
427 virtual void setMemoryAllocator(SkBitmap::Allocator* allocator) | |
428 { | |
429 // FIXME: this doesn't work for images with multiple frames. | |
430 if (m_frameBufferCache.isEmpty()) { | |
431 m_frameBufferCache.resize(1); | |
432 m_frameBufferCache[0].setRequiredPreviousFrameIndex( | |
433 findRequiredPreviousFrame(0, false)); | |
434 } | |
435 m_frameBufferCache[0].setMemoryAllocator(allocator); | |
436 } | |
437 | |
438 protected: | |
439 // Calculates the most recent frame whose image data may be needed in | |
440 // order to decode frame |frameIndex|, based on frame disposal methods | |
441 // and |frameRectIsOpaque|, where |frameRectIsOpaque| signifies whether | |
442 // the rectangle of frame at |frameIndex| is known to be opaque. | |
443 // If no previous frame's data is required, returns WTF::kNotFound. | |
444 // | |
445 // This function requires that the previous frame's | |
446 // |m_requiredPreviousFrameIndex| member has been set correctly. The | |
447 // easiest way to ensure this is for subclasses to call this method and | |
448 // store the result on the frame via setRequiredPreviousFrameIndex() | |
449 // as soon as the frame has been created and parsed sufficiently to | |
450 // determine the disposal method; assuming this happens for all frames | |
451 // in order, the required invariant will hold. | |
452 // | |
453 // Image formats which do not use more than one frame do not need to | |
454 // worry about this; see comments on | |
455 // ImageFrame::m_requiredPreviousFrameIndex. | |
456 size_t findRequiredPreviousFrame(size_t frameIndex, bool frameRectIsOpaq
ue); | |
457 | |
458 virtual void clearFrameBuffer(size_t frameIndex); | |
459 | |
460 RefPtr<SharedBuffer> m_data; // The encoded data. | |
461 Vector<ImageFrame, 1> m_frameBufferCache; | |
462 bool m_premultiplyAlpha; | |
463 bool m_ignoreGammaAndColorProfile; | |
464 ImageOrientation m_orientation; | |
465 | |
466 // The maximum amount of memory a decoded image should require. Ideally, | |
467 // image decoders should downsample large images to fit under this limit | |
468 // (and then return the downsampled size from decodedSize()). Ignoring | |
469 // this limit can cause excessive memory use or even crashes on low- | |
470 // memory devices. | |
471 size_t m_maxDecodedBytes; | |
472 | |
473 private: | |
474 // Some code paths compute the size of the image as "width * height * 4" | |
475 // and return it as a (signed) int. Avoid overflow. | |
476 static bool sizeCalculationMayOverflow(unsigned width, unsigned height) | |
477 { | |
478 unsigned long long total_size = static_cast<unsigned long long>(widt
h) | |
479 * static_cast<unsigned long long>(heig
ht); | |
480 return total_size > ((1 << 29) - 1); | |
481 } | |
482 | |
483 IntSize m_size; | |
484 bool m_sizeAvailable; | |
485 bool m_isAllDataReceived; | |
486 bool m_failed; | |
487 }; | |
488 | |
489 } // namespace WebCore | |
490 | |
491 #endif | |
OLD | NEW |