summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/image-decoders/ImageDecoder.h
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/image-decoders/ImageDecoder.h')
-rw-r--r--WebCore/platform/image-decoders/ImageDecoder.h210
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