/* * 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 "third_party/skia/include/core/SkBitmap.h" #include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/PassRefPtr.h" 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 { FrameEmpty, FramePartial, FrameComplete }; 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. DisposeNotSpecified, // Leave frame in framebuffer DisposeKeep, // Leave frame in framebuffer DisposeOverwriteBgcolor, // Clear frame to fully transparent DisposeOverwritePrevious // 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). BlendAtopPreviousFrame, // Blend non-opaque pixels against fully transparent (i.e. simply // overwrite the corresponding pixels). BlendAtopBgcolor, }; typedef uint32_t PixelData; ImageFrame(); // The assignment operator reads m_hasAlpha (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 m_hasAlpha to some value before calling the operator // lest any tools complain about using an uninitialized value. ImageFrame(const ImageFrame& other) : m_hasAlpha(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&); // Copies the pixel data at [(startX, startY), (endX, startY)) to the // same X-coordinates on each subsequent row up to but not including // endY. void copyRowNTimes(int startX, int endX, int startY, int endY) { ASSERT(startX < width()); ASSERT(endX <= width()); ASSERT(startY < height()); ASSERT(endY <= height()); const int rowBytes = (endX - startX) * sizeof(PixelData); const PixelData* const startAddr = getAddr(startX, startY); for (int destY = startY + 1; destY < endY; ++destY) memcpy(getAddr(startX, destY), startAddr, rowBytes); } // Allocates space for the pixel data. Must be called before any pixels // are written. Must only be called once. Returns whether allocation // succeeded. bool setSize(int newWidth, int newHeight); // Returns a caller-owned pointer to the underlying native image data. // (Actual use: This pointer will be owned by BitmapImage and freed in // FrameData::clear()). const SkBitmap& bitmap() const; bool hasAlpha() const; const IntRect& originalFrameRect() const { return m_originalFrameRect; } Status status() const { return m_status; } unsigned duration() const { return m_duration; } DisposalMethod disposalMethod() const { return m_disposalMethod; } AlphaBlendSource alphaBlendSource() const { return m_alphaBlendSource; } bool premultiplyAlpha() const { return m_premultiplyAlpha; } SkBitmap::Allocator* allocator() const { return m_allocator; } const SkBitmap& getSkBitmap() const { return m_bitmap; } // Returns true if the pixels changed, but the bitmap has not yet been notified. bool pixelsChanged() const { return m_pixelsChanged; } size_t requiredPreviousFrameIndex() const { return m_requiredPreviousFrameIndex; } void setHasAlpha(bool alpha); void setOriginalFrameRect(const IntRect& r) { m_originalFrameRect = r; } void setStatus(Status); void setDuration(unsigned duration) { m_duration = duration; } void setDisposalMethod(DisposalMethod disposalMethod) { m_disposalMethod = disposalMethod; } void setAlphaBlendSource(AlphaBlendSource alphaBlendSource) { m_alphaBlendSource = alphaBlendSource; } void setPremultiplyAlpha(bool premultiplyAlpha) { m_premultiplyAlpha = premultiplyAlpha; } void setMemoryAllocator(SkBitmap::Allocator* allocator) { m_allocator = allocator; } // The pixelsChanged 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 was made. void setPixelsChanged(bool pixelsChanged) { m_pixelsChanged = pixelsChanged; } void setRequiredPreviousFrameIndex(size_t previousFrameIndex) { m_requiredPreviousFrameIndex = previousFrameIndex; } inline PixelData* getAddr(int x, int y) { return m_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 (m_premultiplyAlpha) 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 { RoundFractionControl = 257 * 128 }; if (a < 255) { unsigned alpha = a * 257; r = (r * alpha + RoundFractionControl) >> 16; g = (g * alpha + RoundFractionControl) >> 16; b = (b * alpha + RoundFractionControl) >> 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); } // Notifies the SkBitmap if any pixels changed and resets the flag. inline void notifyBitmapIfPixelsChanged() { if (m_pixelsChanged) m_bitmap.notifyPixelsChanged(); m_pixelsChanged = false; } private: int width() const { return m_bitmap.width(); } int height() const { return m_bitmap.height(); } SkBitmap m_bitmap; SkBitmap::Allocator* m_allocator; bool m_hasAlpha; // 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 m_originalFrameRect; Status m_status; unsigned m_duration; DisposalMethod m_disposalMethod; AlphaBlendSource m_alphaBlendSource; bool m_premultiplyAlpha; // True if the pixels changed, but the bitmap has not yet been notified. bool m_pixelsChanged; // 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 m_requiredPreviousFrameIndex; }; } // namespace blink #endif