|  | /* | 
|  | * 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 ImageFrame_h | 
|  | #define ImageFrame_h | 
|  |  | 
|  | #include "platform/PlatformExport.h" | 
|  | #include "platform/geometry/IntRect.h" | 
|  | #include "platform/wtf/Allocator.h" | 
|  | #include "platform/wtf/Assertions.h" | 
|  | #include "platform/wtf/Time.h" | 
|  | #include "public/platform/WebVector.h" | 
|  | #include "third_party/skia/include/core/SkBitmap.h" | 
|  | #include "third_party/skia/include/core/SkColorPriv.h" | 
|  |  | 
|  | class SkImage; | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | // ImageFrame represents the decoded image data.  This buffer is what all | 
|  | // decoders write a single frame into. | 
|  | class PLATFORM_EXPORT ImageFrame final { | 
|  | DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); | 
|  |  | 
|  | public: | 
|  | enum Status { kFrameEmpty, kFramePartial, kFrameComplete }; | 
|  | enum DisposalMethod { | 
|  | // If you change the numeric values of these, make sure you audit | 
|  | // all users, as some users may cast raw values to/from these | 
|  | // constants. | 
|  | kDisposeNotSpecified,      // Leave frame in framebuffer | 
|  | kDisposeKeep,              // Leave frame in framebuffer | 
|  | kDisposeOverwriteBgcolor,  // Clear frame to fully transparent | 
|  | kDisposeOverwritePrevious  // Clear frame to previous framebuffer contents | 
|  | }; | 
|  | // Indicates how non-opaque pixels in the current frame rectangle | 
|  | // are blended with those in the previous frame. | 
|  | // Notes: | 
|  | // * GIF always uses 'BlendAtopPreviousFrame'. | 
|  | // * WebP also uses the 'BlendAtopBgcolor' option. This is useful for | 
|  | //   cases where one wants to transform a few opaque pixels of the | 
|  | //   previous frame into non-opaque pixels in the current frame. | 
|  | enum AlphaBlendSource { | 
|  | // Blend non-opaque pixels atop the corresponding pixels in the | 
|  | // initial buffer state (i.e. any previous frame buffer after having | 
|  | // been properly disposed). | 
|  | kBlendAtopPreviousFrame, | 
|  |  | 
|  | // Blend non-opaque pixels against fully transparent (i.e. simply | 
|  | // overwrite the corresponding pixels). | 
|  | kBlendAtopBgcolor, | 
|  | }; | 
|  | typedef uint32_t PixelData; | 
|  |  | 
|  | typedef WebVector<char> ICCProfile; | 
|  |  | 
|  | ImageFrame(); | 
|  |  | 
|  | // The assignment operator reads has_alpha_ (inside SetStatus()) before it | 
|  | // sets it (in SetHasAlpha()).  This doesn't cause any problems, since the | 
|  | // SetHasAlpha() call ensures all state is set correctly, but it means we | 
|  | // need to initialize has_alpha_ to some value before calling the operator | 
|  | // lest any tools complain about using an uninitialized value. | 
|  | ImageFrame(const ImageFrame& other) : has_alpha_(false) { operator=(other); } | 
|  |  | 
|  | // For backends which refcount their data, this operator doesn't need to | 
|  | // create a new copy of the image data, only increase the ref count. | 
|  | ImageFrame& operator=(const ImageFrame& other); | 
|  |  | 
|  | // These do not touch other metadata, only the raw pixel data. | 
|  | void ClearPixelData(); | 
|  | void ZeroFillPixelData(); | 
|  | void ZeroFillFrameRect(const IntRect&); | 
|  |  | 
|  | // Makes this frame have an independent copy of the provided image's | 
|  | // pixel data, so that modifications in one frame are not reflected in | 
|  | // the other.  Returns whether the copy succeeded. | 
|  | bool CopyBitmapData(const ImageFrame&); | 
|  |  | 
|  | // Moves the bitmap data from the provided frame to this one, leaving the | 
|  | // provided frame empty.  Operation is successful only if bitmap data is not | 
|  | // marked as done (immutable).  Returns whether the move succeeded. | 
|  | bool TakeBitmapDataIfWritable(ImageFrame*); | 
|  |  | 
|  | // Copies the pixel data at [(start_x, start_y), (end_x, start_y)) to the | 
|  | // same X-coordinates on each subsequent row up to but not including | 
|  | // end_y. | 
|  | void CopyRowNTimes(int start_x, int end_x, int start_y, int end_y) { | 
|  | DCHECK_LT(start_x, Width()); | 
|  | DCHECK_LE(end_x, Width()); | 
|  | DCHECK_LT(start_y, Height()); | 
|  | DCHECK_LE(end_y, Height()); | 
|  | const int row_bytes = (end_x - start_x) * sizeof(PixelData); | 
|  | const PixelData* const start_addr = GetAddr(start_x, start_y); | 
|  | for (int dest_y = start_y + 1; dest_y < end_y; ++dest_y) | 
|  | memcpy(GetAddr(start_x, dest_y), start_addr, row_bytes); | 
|  | } | 
|  |  | 
|  | // Allocates space for the pixel data. Must be called before any pixels are | 
|  | // written, and should only be called once. The specified color space may be | 
|  | // null if and only if color correct rendering is enabled. Returns true if the | 
|  | // allocation succeeded. | 
|  | bool AllocatePixelData(int new_width, int new_height, sk_sp<SkColorSpace>); | 
|  |  | 
|  | bool HasAlpha() const; | 
|  | const IntRect& OriginalFrameRect() const { return original_frame_rect_; } | 
|  | Status GetStatus() const { return status_; } | 
|  | TimeDelta Duration() const { return duration_; } | 
|  | DisposalMethod GetDisposalMethod() const { return disposal_method_; } | 
|  | AlphaBlendSource GetAlphaBlendSource() const { return alpha_blend_source_; } | 
|  | bool PremultiplyAlpha() const { return premultiply_alpha_; } | 
|  | SkBitmap::Allocator* GetAllocator() const { return allocator_; } | 
|  |  | 
|  | // Returns the bitmap that is the output of decoding. | 
|  | const SkBitmap& Bitmap() const { return bitmap_; } | 
|  |  | 
|  | // Create SkImage from Bitmap() and return it.  This should be called only | 
|  | // if frame is complete.  The bitmap is set immutable before creating | 
|  | // SkImage to avoid copying bitmap in SkImage::MakeFromBitmap(bitmap_). | 
|  | sk_sp<SkImage> FinalizePixelsAndGetImage(); | 
|  |  | 
|  | // Returns true if the pixels changed, but the bitmap has not yet been | 
|  | // notified. | 
|  | bool PixelsChanged() const { return pixels_changed_; } | 
|  | size_t RequiredPreviousFrameIndex() const { | 
|  | return required_previous_frame_index_; | 
|  | } | 
|  | void SetHasAlpha(bool alpha); | 
|  | void SetOriginalFrameRect(const IntRect& r) { original_frame_rect_ = r; } | 
|  | void SetStatus(Status); | 
|  | void SetDuration(TimeDelta duration) { duration_ = duration; } | 
|  | void SetDisposalMethod(DisposalMethod disposal_method) { | 
|  | disposal_method_ = disposal_method; | 
|  | } | 
|  | void SetAlphaBlendSource(AlphaBlendSource alpha_blend_source) { | 
|  | alpha_blend_source_ = alpha_blend_source; | 
|  | } | 
|  | void SetPremultiplyAlpha(bool premultiply_alpha) { | 
|  | premultiply_alpha_ = premultiply_alpha; | 
|  | } | 
|  | void SetMemoryAllocator(SkBitmap::Allocator* allocator) { | 
|  | allocator_ = allocator; | 
|  | } | 
|  | // The pixels_changed flag needs to be set when the raw pixel data was | 
|  | // directly modified (e.g. through a pointer or SetRGBA). The flag is usually | 
|  | // set after a batch of changes has been made. | 
|  | void SetPixelsChanged(bool pixels_changed) { | 
|  | pixels_changed_ = pixels_changed; | 
|  | } | 
|  | void SetRequiredPreviousFrameIndex(size_t previous_frame_index) { | 
|  | required_previous_frame_index_ = previous_frame_index; | 
|  | } | 
|  |  | 
|  | inline PixelData* GetAddr(int x, int y) { return bitmap_.getAddr32(x, y); } | 
|  |  | 
|  | inline void SetRGBA(int x, | 
|  | int y, | 
|  | unsigned r, | 
|  | unsigned g, | 
|  | unsigned b, | 
|  | unsigned a) { | 
|  | SetRGBA(GetAddr(x, y), r, g, b, a); | 
|  | } | 
|  |  | 
|  | inline void SetRGBA(PixelData* dest, | 
|  | unsigned r, | 
|  | unsigned g, | 
|  | unsigned b, | 
|  | unsigned a) { | 
|  | if (premultiply_alpha_) | 
|  | SetRGBAPremultiply(dest, r, g, b, a); | 
|  | else | 
|  | *dest = SkPackARGB32NoCheck(a, r, g, b); | 
|  | } | 
|  |  | 
|  | static inline void SetRGBAPremultiply(PixelData* dest, | 
|  | unsigned r, | 
|  | unsigned g, | 
|  | unsigned b, | 
|  | unsigned a) { | 
|  | enum FractionControl { kRoundFractionControl = 257 * 128 }; | 
|  |  | 
|  | if (a < 255) { | 
|  | unsigned alpha = a * 257; | 
|  | r = (r * alpha + kRoundFractionControl) >> 16; | 
|  | g = (g * alpha + kRoundFractionControl) >> 16; | 
|  | b = (b * alpha + kRoundFractionControl) >> 16; | 
|  | } | 
|  |  | 
|  | *dest = SkPackARGB32NoCheck(a, r, g, b); | 
|  | } | 
|  |  | 
|  | static inline void SetRGBARaw(PixelData* dest, | 
|  | unsigned r, | 
|  | unsigned g, | 
|  | unsigned b, | 
|  | unsigned a) { | 
|  | *dest = SkPackARGB32NoCheck(a, r, g, b); | 
|  | } | 
|  |  | 
|  | // Blend the RGBA pixel provided by |red|, |green|, |blue| and |alpha| over | 
|  | // the pixel in |dest|, without premultiplication, and overwrite |dest| with | 
|  | // the result. | 
|  | static void BlendRGBARaw(PixelData* dest, | 
|  | unsigned red, | 
|  | unsigned green, | 
|  | unsigned blue, | 
|  | unsigned alpha); | 
|  |  | 
|  | // Blend the pixel, without premultiplication, in |src| over |dst| and | 
|  | // overwrite |src| with the result. | 
|  | static void BlendSrcOverDstRaw(PixelData* src, PixelData dst); | 
|  |  | 
|  | // Blend the RGBA pixel provided by |r|, |g|, |b|, |a| over the pixel in | 
|  | // |dest| and overwrite |dest| with the result. Premultiply the pixel values | 
|  | // before blending. | 
|  | static inline void BlendRGBAPremultiplied(PixelData* dest, | 
|  | unsigned r, | 
|  | unsigned g, | 
|  | unsigned b, | 
|  | unsigned a) { | 
|  | // If the new pixel is completely transparent, no operation is necessary | 
|  | // since |dest| contains the background pixel. | 
|  | if (a == 0x0) | 
|  | return; | 
|  |  | 
|  | // If the new pixel is opaque, no need for blending - just write the pixel. | 
|  | if (a == 0xFF) { | 
|  | SetRGBAPremultiply(dest, r, g, b, a); | 
|  | return; | 
|  | } | 
|  |  | 
|  | PixelData src; | 
|  | SetRGBAPremultiply(&src, r, g, b, a); | 
|  | *dest = SkPMSrcOver(src, *dest); | 
|  | } | 
|  |  | 
|  | // Blend the pixel in |src| over |dst| and overwrite |src| with the result. | 
|  | static inline void BlendSrcOverDstPremultiplied(PixelData* src, | 
|  | PixelData dst) { | 
|  | *src = SkPMSrcOver(*src, dst); | 
|  | } | 
|  |  | 
|  | // Notifies the SkBitmap if any pixels changed and resets the flag. | 
|  | inline void NotifyBitmapIfPixelsChanged() { | 
|  | if (pixels_changed_) | 
|  | bitmap_.notifyPixelsChanged(); | 
|  | pixels_changed_ = false; | 
|  | } | 
|  |  | 
|  | private: | 
|  | int Width() const { return bitmap_.width(); } | 
|  |  | 
|  | int Height() const { return bitmap_.height(); } | 
|  |  | 
|  | SkAlphaType ComputeAlphaType() const; | 
|  |  | 
|  | SkBitmap bitmap_; | 
|  | SkBitmap::Allocator* allocator_; | 
|  | bool has_alpha_; | 
|  | // This will always just be the entire buffer except for GIF or WebP | 
|  | // frames whose original rect was smaller than the overall image size. | 
|  | IntRect original_frame_rect_; | 
|  | Status status_; | 
|  | TimeDelta duration_; | 
|  | DisposalMethod disposal_method_; | 
|  | AlphaBlendSource alpha_blend_source_; | 
|  | bool premultiply_alpha_; | 
|  | // True if the pixels changed, but the bitmap has not yet been notified. | 
|  | bool pixels_changed_; | 
|  |  | 
|  | // The frame that must be decoded before this frame can be decoded. | 
|  | // WTF::kNotFound if this frame doesn't require any previous frame. | 
|  | // This is used by ImageDecoder::ClearCacheExceptFrame(), and will never | 
|  | // be read for image formats that do not have multiple frames. | 
|  | size_t required_previous_frame_index_; | 
|  | }; | 
|  |  | 
|  | }  // namespace blink | 
|  |  | 
|  | #endif |