blob: 6ad4ed48b6f9b4a53aba86d1aa2c173a5fda4c64 [file] [log] [blame]
/*
* 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