diff options
Diffstat (limited to 'WebCore/platform/image-decoders/ImageDecoder.h')
-rw-r--r-- | WebCore/platform/image-decoders/ImageDecoder.h | 210 |
1 files changed, 162 insertions, 48 deletions
diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index ca27b37..ffc7d9e 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -30,18 +30,22 @@ #include "ImageSource.h" #include "PlatformString.h" #include "SharedBuffer.h" +#include <wtf/Assertions.h> +#include <wtf/RefPtr.h> #include <wtf/Vector.h> -namespace WebCore { +#if PLATFORM(SKIA) +#include "NativeImageSkia.h" +#include "SkBitmap.h" +#endif - typedef Vector<unsigned> RGBA32Array; +namespace WebCore { // The RGBA32Buffer object represents the decoded image data in RGBA32 format. This buffer is what all // decoders write a single frame into. Frames are then instantiated for drawing by being handed this buffer. class RGBA32Buffer { public: enum FrameStatus { FrameEmpty, FramePartial, FrameComplete }; - enum FrameDisposalMethod { // 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. @@ -50,46 +54,101 @@ namespace WebCore { DisposeOverwriteBgcolor, // Clear frame to transparent DisposeOverwritePrevious, // Clear frame to previous framebuffer contents }; +#if PLATFORM(SKIA) + typedef uint32_t PixelData; +#else + typedef unsigned PixelData; +#endif + + RGBA32Buffer(); + + // For backends which refcount their data, this constructor doesn't need + // to create a new copy of the image data, only increase the ref count. + // + // This exists because ImageDecoder keeps a Vector<RGBA32Buffer>, and + // Vector requires this constructor. + RGBA32Buffer(const RGBA32Buffer& other) + { + operator=(other); + } + + // Deletes the pixel data entirely; used by ImageDecoder to save memory + // when we no longer need to display a frame and only need its metadata. + void clear(); + + // Zeroes the pixel data in the buffer, setting it to fully-transparent. + void zeroFill(); + + // Creates a new copy of the image data in |other|, so the two images + // can be modified independently. + void copyBitmapData(const RGBA32Buffer& other); - RGBA32Buffer() - : m_height(0) - , m_status(FrameEmpty) - , m_duration(0) - , m_disposalMethod(DisposeNotSpecified) - , m_hasAlpha(false) + // 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) { - } - - void clear() { - m_bytes.clear(); - m_status = FrameEmpty; - // NOTE: Do not reset other members here; clearFrameBufferCache() calls - // this to free the bitmap data, but other functions like - // initFrameBuffer() and frameComplete() may still need to read other - // metadata out of this frame later. + 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); } - const RGBA32Array& bytes() const { return m_bytes; } - RGBA32Array& bytes() { return m_bytes; } + // Allocates space for the pixel data. Must be called before any pixels + // are written. Will return true on success, false if the memory + // allocation fails. Calling this multiple times is undefined and may + // leak memory. + bool setSize(int newWidth, int newHeight); + + // To be used by ImageSource::createFrameAtIndex(). Returns a pointer + // to the underlying native image data. This pointer will be owned by + // the BitmapImage and freed in FrameData::clear(). + NativeImagePtr asNewNativeImage() const; + + bool hasAlpha() const; const IntRect& rect() const { return m_rect; } - unsigned height() const { return m_height; } FrameStatus status() const { return m_status; } unsigned duration() const { return m_duration; } FrameDisposalMethod disposalMethod() const { return m_disposalMethod; } - bool hasAlpha() const { return m_hasAlpha; } + void setHasAlpha(bool alpha); void setRect(const IntRect& r) { m_rect = r; } - void ensureHeight(unsigned rowIndex) { if (rowIndex > m_height) m_height = rowIndex; } - void setStatus(FrameStatus s) { m_status = s; } + void setStatus(FrameStatus status); void setDuration(unsigned duration) { m_duration = duration; } void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; } - void setHasAlpha(bool alpha) { m_hasAlpha = alpha; } - static void setRGBA(unsigned& pos, unsigned r, unsigned g, unsigned b, unsigned a) + inline void setRGBA(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a) + { + setRGBA(getAddr(x, y), r, g, b, a); + } + + private: + RGBA32Buffer& operator=(const RGBA32Buffer& other); + + int width() const; + int height() const; + + inline PixelData* getAddr(int x, int y) + { +#if PLATFORM(CAIRO) || PLATFORM(WX) + return m_bytes.data() + (y * width()) + x; +#elif PLATFORM(SKIA) + return m_bitmap.getAddr32(x, y); +#else + ASSERT_NOT_REACHED(); + return 0; +#endif + } + + inline void setRGBA(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a) { // We store this data pre-multiplied. if (a == 0) - pos = 0; + *dest = 0; else { if (a < 255) { float alphaPercent = a / 255.0f; @@ -97,20 +156,25 @@ namespace WebCore { g = static_cast<unsigned>(g * alphaPercent); b = static_cast<unsigned>(b * alphaPercent); } - pos = (a << 24 | r << 16 | g << 8 | b); + *dest = (a << 24 | r << 16 | g << 8 | b); } } - private: - RGBA32Array m_bytes; - IntRect m_rect; // The rect of the original specified frame within the overall buffer. - // This will always just be the entire buffer except for GIF frames - // whose original rect was smaller than the overall image size. - unsigned m_height; // The height (the number of rows we've fully decoded). +#if PLATFORM(CAIRO) || PLATFORM(WX) + Vector<PixelData> m_bytes; + IntSize m_size; // The size of the buffer. This should be the + // same as ImageDecoder::m_size. + bool m_hasAlpha; // Whether or not any of the pixels in the buffer have transparency. +#elif PLATFORM(SKIA) + NativeImageSkia m_bitmap; +#endif + IntRect m_rect; // The rect of the original specified frame within the overall buffer. + // This will always just be the entire buffer except for GIF frames + // whose original rect was smaller than the overall image size. FrameStatus m_status; // Whether or not this frame is completely finished decoding. - unsigned m_duration; // The animation delay. - FrameDisposalMethod m_disposalMethod; // What to do with this frame's data when initializing the next frame. - bool m_hasAlpha; // Whether or not any of the pixels in the buffer have transparency. + unsigned m_duration; // The animation delay. + FrameDisposalMethod m_disposalMethod; + // What to do with this frame's data when initializing the next frame. }; // The ImageDecoder class represents a base class for specific image format decoders @@ -119,11 +183,11 @@ namespace WebCore { class ImageDecoder { public: ImageDecoder() - : m_sizeAvailable(false) - , m_failed(false) + : m_failed(false) + , m_sizeAvailable(false) { } - + virtual ~ImageDecoder() {} // The the filename extension usually associated with an undecoded image of this type. @@ -132,16 +196,53 @@ namespace WebCore { // All specific decoder plugins must do something with the data they are given. virtual void setData(SharedBuffer* data, bool allDataReceived) { m_data = data; } - // Whether or not the size information has been decoded yet. - virtual bool isSizeAvailable() const = 0; + // Whether or not the size information has been decoded yet. This default + // implementation just returns true if the size has been set and we have not + // seen a failure. Decoders may want to override this to lazily decode + // enough of the image to get the size. + virtual bool isSizeAvailable() + { + return !m_failed && m_sizeAvailable; + } + + // Returns the size of the image. + virtual IntSize size() const + { + // Requesting the size of an invalid bitmap is meaningless. + ASSERT(!m_failed); + return m_size; + } + + // Returns the size of frame |index|. This will only differ from size() + // for formats where different frames are different sizes (namely ICO, + // where each frame represents a different icon within the master file). + // Notably, this does not return different sizes for different GIF + // frames, since while these may be stored as smaller rectangles, during + // decoding they are composited to create a full-size frame. + virtual IntSize frameSizeAtIndex(size_t) const + { + return size(); + } - // Requests the size. - virtual IntSize size() const { return m_size; } + // Called by the image decoders to set their decoded size, this also check + // the size for validity. It will return true if the size was set, or false + // if there is an error. On error, the m_failed flag will be set and the + // caller should immediately stop decoding. + virtual bool setSize(unsigned width, unsigned height) + { + if (isOverSize(width, height)) { + m_failed = true; + return false; + } + m_size = IntSize(width, height); + m_sizeAvailable = true; + return true; + } // The total number of frames for the image. Classes that support multiple frames // will scan the image data for the answer if they need to (without necessarily // decoding all of the individual frames). - virtual int frameCount() { return 1; } + virtual size_t frameCount() { return 1; } // The number of repetitions to perform for an animation loop. virtual int repetitionCount() const { return cAnimationNone; } @@ -149,7 +250,7 @@ namespace WebCore { // Called to obtain the RGBA32Buffer full of decoded data for rendering. The // decoder plugin will decode as much of the frame as it can before handing // back the buffer. - virtual RGBA32Buffer* frameBufferAtIndex(size_t index) = 0; + virtual RGBA32Buffer* frameBufferAtIndex(size_t) = 0; // Whether or not the underlying image format even supports alpha transparency. virtual bool supportsAlpha() const { return true; } @@ -168,9 +269,22 @@ namespace WebCore { protected: RefPtr<SharedBuffer> m_data; // The encoded data. Vector<RGBA32Buffer> m_frameBufferCache; - bool m_sizeAvailable; - mutable bool m_failed; + bool m_failed; + + private: + // Some code paths compute the size of the image as "width * height * 4" + // and return it as a (signed) int. Avoid overflow. + static bool isOverSize(unsigned width, unsigned height) + { + // width * height must not exceed (2 ^ 29) - 1, so that we don't + // overflow when we multiply by 4. + unsigned long long total_size = static_cast<unsigned long long>(width) + * static_cast<unsigned long long>(height); + return total_size > ((1 << 29) - 1); + } + IntSize m_size; + bool m_sizeAvailable; }; } // namespace WebCore |