| /* |
| * 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_IMAGE_FRAME_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_IMAGE_FRAME_H_ |
| |
| #include "third_party/blink/public/platform/web_vector.h" |
| #include "third_party/blink/renderer/platform/geometry/int_rect.h" |
| #include "third_party/blink/renderer/platform/platform_export.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator.h" |
| #include "third_party/blink/renderer/platform/wtf/assertions.h" |
| #include "third_party/blink/renderer/platform/wtf/time.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(); |
| |
| public: |
| enum PixelFormat { kN32, kRGBA_F16 }; |
| enum Status { kFrameEmpty, kFrameInitialized, 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 uint64_t PixelDataF16; |
| |
| 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(pixel_format_ == kN32); |
| 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 { return has_alpha_; } |
| PixelFormat GetPixelFormat() const { return pixel_format_; } |
| 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 SetPixelFormat(PixelFormat format) { pixel_format_ = format; } |
| 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) { |
| DCHECK(pixel_format_ == kN32); |
| return bitmap_.getAddr32(x, y); |
| } |
| |
| inline PixelDataF16* GetAddrF16(int x, int y) { |
| DCHECK(pixel_format_ == kRGBA_F16); |
| SkPixmap pixmap; |
| if (!bitmap_.peekPixels(&pixmap)) |
| NOTREACHED(); |
| return pixmap.writable_addr64(x, y); |
| } |
| |
| inline void SetRGBA(int x, |
| int y, |
| unsigned r, |
| unsigned g, |
| unsigned b, |
| unsigned a) { |
| DCHECK(pixel_format_ == kN32); |
| SetRGBA(GetAddr(x, y), r, g, b, a); |
| } |
| |
| inline void SetRGBA(PixelData* dest, |
| unsigned r, |
| unsigned g, |
| unsigned b, |
| unsigned a) { |
| DCHECK(pixel_format_ == kN32); |
| 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); |
| |
| static void BlendRGBARawF16Buffer(PixelDataF16* dst, |
| PixelDataF16* src, |
| size_t num_pixels); |
| |
| // 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); |
| } |
| |
| static void BlendRGBAPremultipliedF16Buffer(PixelDataF16* dst, |
| PixelDataF16* src, |
| size_t num_pixels); |
| |
| // 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_; |
| PixelFormat pixel_format_; |
| // 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 |