| /* | 
 |  * 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 <optional> | 
 |  | 
 | #include "base/check_op.h" | 
 | #include "base/compiler_specific.h" | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/notreached.h" | 
 | #include "base/time/time.h" | 
 | #include "skia/ext/pmcolor_utils.h" | 
 | #include "third_party/blink/renderer/platform/platform_export.h" | 
 | #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" | 
 | #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" | 
 | #include "third_party/skia/include/core/SkBitmap.h" | 
 | #include "third_party/skia/include/core/SkImage.h" | 
 | #include "third_party/skia/include/core/SkPixmap.h" | 
 | #include "third_party/skia/include/private/chromium/SkPMColor.h" | 
 | #include "ui/gfx/geometry/rect.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; | 
 |  | 
 |   ImageFrame(); | 
 |   ~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); | 
 |  | 
 |   // 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 gfx::Rect&); | 
 |  | 
 |   // 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) { | 
 |       UNSAFE_TODO(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. | 
 |   [[nodiscard]] bool AllocatePixelData(int new_width, | 
 |                                        int new_height, | 
 |                                        sk_sp<SkColorSpace>); | 
 |  | 
 |   bool HasAlpha() const { return has_alpha_; } | 
 |   PixelFormat GetPixelFormat() const { return pixel_format_; } | 
 |   const gfx::Rect& OriginalFrameRect() const { return original_frame_rect_; } | 
 |   Status GetStatus() const { return status_; } | 
 |   std::optional<base::TimeDelta> Timestamp() const { return timestamp_; } | 
 |   base::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 SkImages::RasterFromBitmap(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_; } | 
 |   wtf_size_t RequiredPreviousFrameIndex() const { | 
 |     return required_previous_frame_index_; | 
 |   } | 
 |   void SetHasAlpha(bool alpha); | 
 |   void SetPixelFormat(PixelFormat format) { pixel_format_ = format; } | 
 |   void SetOriginalFrameRect(const gfx::Rect& r) { original_frame_rect_ = r; } | 
 |   void SetStatus(Status); | 
 |   void SetTimestamp(base::TimeDelta timestamp) { timestamp_ = timestamp; } | 
 |   void SetDuration(base::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(wtf_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 = SkPMColorSetARGB(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 = SkPMColorSetARGB(a, r, g, b); | 
 |   } | 
 |  | 
 |   static inline void SetRGBARaw(PixelData* dest, | 
 |                                 unsigned r, | 
 |                                 unsigned g, | 
 |                                 unsigned b, | 
 |                                 unsigned a) { | 
 |     *dest = SkPMColorSetARGB(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 in |src| over |dst| and overwrite |src| with the result. | 
 |   // This requires |src| and |dst| to not have alpha premultiplied on the rgb | 
 |   // channels. | 
 |   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 = skia::BlendSrcOver(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. | 
 |   // This requires |src| and |dst| to be premultiplied already. | 
 |   static inline void BlendSrcOverDstPremultiplied(PixelData* src, | 
 |                                                   PixelData dst) { | 
 |     *src = skia::BlendSrcOver(*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_; | 
 |   raw_ptr<SkBitmap::Allocator> allocator_ = nullptr; | 
 |   bool has_alpha_ = true; | 
 |   PixelFormat pixel_format_ = kN32; | 
 |   // This will always just be the entire buffer except for GIF or WebP | 
 |   // frames whose original rect was smaller than the overall image size. | 
 |   gfx::Rect original_frame_rect_; | 
 |   Status status_ = kFrameEmpty; | 
 |   std::optional<base::TimeDelta> timestamp_; | 
 |   base::TimeDelta duration_; | 
 |   DisposalMethod disposal_method_ = kDisposeNotSpecified; | 
 |   AlphaBlendSource alpha_blend_source_ = kBlendAtopPreviousFrame; | 
 |   bool premultiply_alpha_ = true; | 
 |   // True if the pixels changed, but the bitmap has not yet been notified. | 
 |   bool pixels_changed_ = false; | 
 |  | 
 |   // The frame that must be decoded before this frame can be decoded. | 
 |   // 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. | 
 |   wtf_size_t required_previous_frame_index_ = kNotFound; | 
 | }; | 
 |  | 
 | }  // namespace blink | 
 |  | 
 | #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_IMAGE_FRAME_H_ |