Commit 6b9aef2c authored by pkasting@chromium.org's avatar pkasting@chromium.org

2009-06-11 Peter Kasting <pkasting@google.com>

        Reviewed by Eric Seidel.

        https://bugs.webkit.org/show_bug.cgi?id=25709 part seven
        Update Skia's ImageDecoder.h with a few changes designed to reduce the
        delta between specific implementations of ImageDecoder.h.  Update
        Cairo's ImageDecoder.h to sync up with the API changes in the Skia
        version in the last two chage sets.  Update Cairo's PNG/JPEG/GIF
        decoders to use the APIs as well.  All the Cairo image decoder changes
        are direct copies of the Skia versions except ImageDecoder.h, which is
        modified in the necessary ways for the differences between Cairo and
        Skia.

        * platform/graphics/cairo/ImageSourceCairo.cpp:
        (WebCore::ImageSource::createFrameAtIndex): Use new RGBA32Buffer::asNewNativeImage() API.
        * platform/image-decoders/ImageDecoder.h: Sync up with Skia version.
        (WebCore::RGBA32Buffer::):
        (WebCore::RGBA32Buffer::RGBA32Buffer):
        (WebCore::RGBA32Buffer::clear):
        (WebCore::RGBA32Buffer::zeroFill):
        (WebCore::RGBA32Buffer::copyBitmapData):
        (WebCore::RGBA32Buffer::copyRowNTimes):
        (WebCore::RGBA32Buffer::setSize):
        (WebCore::RGBA32Buffer::asNewNativeImage):
        (WebCore::RGBA32Buffer::hasAlpha):
        (WebCore::RGBA32Buffer::disposalMethod):
        (WebCore::RGBA32Buffer::setHasAlpha):
        (WebCore::RGBA32Buffer::setDisposalMethod):
        (WebCore::RGBA32Buffer::setRGBA):
        (WebCore::RGBA32Buffer::operator=):
        (WebCore::RGBA32Buffer::width):
        (WebCore::RGBA32Buffer::height):
        (WebCore::RGBA32Buffer::getAddr):
        * platform/image-decoders/gif/GIFImageDecoder.cpp: Sync up with Skia version.
        (WebCore::GIFImageDecoder::initFrameBuffer):
        (WebCore::GIFImageDecoder::haveDecodedRow):
        * platform/image-decoders/jpeg/JPEGImageDecoder.cpp: Sync up with Skia version.
        (WebCore::JPEGImageDecoder::outputScanlines):
        * platform/image-decoders/png/PNGImageDecoder.cpp: Sync up with Skia version.
        (WebCore::PNGImageDecoder::rowAvailable):
        * platform/image-decoders/skia/ImageDecoder.h: Add various typedefs or helper functions to minimize differences with Cairo version.  Reorder functions slightly to match reordering of Cairo's m_hasAlpha variable, which I moved to increase readability.
        (WebCore::RGBA32Buffer::):
        (WebCore::RGBA32Buffer::copyRowNTimes):
        (WebCore::RGBA32Buffer::setSize):
        (WebCore::RGBA32Buffer::asNewNativeImage):
        (WebCore::RGBA32Buffer::hasAlpha):
        (WebCore::RGBA32Buffer::disposalMethod):
        (WebCore::RGBA32Buffer::setHasAlpha):
        (WebCore::RGBA32Buffer::setStatus):
        (WebCore::RGBA32Buffer::setDisposalMethod):
        (WebCore::RGBA32Buffer::setRGBA):
        (WebCore::RGBA32Buffer::operator=):
        (WebCore::RGBA32Buffer::width):
        (WebCore::RGBA32Buffer::height):
        (WebCore::RGBA32Buffer::getAddr):
        * platform/image-decoders/skia/JPEGImageDecoder.cpp: Add #include needed by JPEG headers on some platforms, plus comment.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@44631 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 147773fa
2009-06-11 Peter Kasting <pkasting@google.com>
Reviewed by Eric Seidel.
https://bugs.webkit.org/show_bug.cgi?id=25709 part seven
Update Skia's ImageDecoder.h with a few changes designed to reduce the
delta between specific implementations of ImageDecoder.h. Update
Cairo's ImageDecoder.h to sync up with the API changes in the Skia
version in the last two chage sets. Update Cairo's PNG/JPEG/GIF
decoders to use the APIs as well. All the Cairo image decoder changes
are direct copies of the Skia versions except ImageDecoder.h, which is
modified in the necessary ways for the differences between Cairo and
Skia.
* platform/graphics/cairo/ImageSourceCairo.cpp:
(WebCore::ImageSource::createFrameAtIndex): Use new RGBA32Buffer::asNewNativeImage() API.
* platform/image-decoders/ImageDecoder.h: Sync up with Skia version.
(WebCore::RGBA32Buffer::):
(WebCore::RGBA32Buffer::RGBA32Buffer):
(WebCore::RGBA32Buffer::clear):
(WebCore::RGBA32Buffer::zeroFill):
(WebCore::RGBA32Buffer::copyBitmapData):
(WebCore::RGBA32Buffer::copyRowNTimes):
(WebCore::RGBA32Buffer::setSize):
(WebCore::RGBA32Buffer::asNewNativeImage):
(WebCore::RGBA32Buffer::hasAlpha):
(WebCore::RGBA32Buffer::disposalMethod):
(WebCore::RGBA32Buffer::setHasAlpha):
(WebCore::RGBA32Buffer::setDisposalMethod):
(WebCore::RGBA32Buffer::setRGBA):
(WebCore::RGBA32Buffer::operator=):
(WebCore::RGBA32Buffer::width):
(WebCore::RGBA32Buffer::height):
(WebCore::RGBA32Buffer::getAddr):
* platform/image-decoders/gif/GIFImageDecoder.cpp: Sync up with Skia version.
(WebCore::GIFImageDecoder::initFrameBuffer):
(WebCore::GIFImageDecoder::haveDecodedRow):
* platform/image-decoders/jpeg/JPEGImageDecoder.cpp: Sync up with Skia version.
(WebCore::JPEGImageDecoder::outputScanlines):
* platform/image-decoders/png/PNGImageDecoder.cpp: Sync up with Skia version.
(WebCore::PNGImageDecoder::rowAvailable):
* platform/image-decoders/skia/ImageDecoder.h: Add various typedefs or helper functions to minimize differences with Cairo version. Reorder functions slightly to match reordering of Cairo's m_hasAlpha variable, which I moved to increase readability.
(WebCore::RGBA32Buffer::):
(WebCore::RGBA32Buffer::copyRowNTimes):
(WebCore::RGBA32Buffer::setSize):
(WebCore::RGBA32Buffer::asNewNativeImage):
(WebCore::RGBA32Buffer::hasAlpha):
(WebCore::RGBA32Buffer::disposalMethod):
(WebCore::RGBA32Buffer::setHasAlpha):
(WebCore::RGBA32Buffer::setStatus):
(WebCore::RGBA32Buffer::setDisposalMethod):
(WebCore::RGBA32Buffer::setRGBA):
(WebCore::RGBA32Buffer::operator=):
(WebCore::RGBA32Buffer::width):
(WebCore::RGBA32Buffer::height):
(WebCore::RGBA32Buffer::getAddr):
* platform/image-decoders/skia/JPEGImageDecoder.cpp: Add #include needed by JPEG headers on some platforms, plus comment.
2009-06-12 Brent Fulgham <bfulgham@webkit.org>
Unreviewed build correction.
......@@ -193,11 +193,7 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
if (!size().height())
return 0;
return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(),
CAIRO_FORMAT_ARGB32,
size().width(),
size().height(),
size().width()*4);
return buffer->asNewNativeImage();
}
bool ImageSource::frameIsCompleteAtIndex(size_t index)
......
......@@ -30,20 +30,18 @@
#include "ImageSource.h"
#include "PlatformString.h"
#include "SharedBuffer.h"
#include <cairo.h>
#include <wtf/Assertions.h>
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
namespace WebCore {
typedef Vector<unsigned> RGBA32Array;
// 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.
......@@ -52,22 +50,37 @@ namespace WebCore {
DisposeOverwriteBgcolor, // Clear frame to transparent
DisposeOverwritePrevious, // Clear frame to previous framebuffer contents
};
typedef unsigned PixelData;
RGBA32Buffer()
: m_status(FrameEmpty)
: m_hasAlpha(false)
, m_status(FrameEmpty)
, m_duration(0)
, m_disposalMethod(DisposeNotSpecified)
, m_hasAlpha(false)
{
}
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.
// This exists because ImageDecoder keeps a Vector<RGBA32Buffer>, and
// Vector requires this constructor.
RGBA32Buffer(const RGBA32Buffer& other)
{
operator=(other);
}
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.
}
void zeroFill()
{
m_bytes.fill(0);
m_hasAlpha = true;
}
// This function creates a new copy of the image data in |other|, so the
......@@ -78,11 +91,25 @@ namespace WebCore {
return;
m_bytes = other.m_bytes;
m_hasAlpha = other.m_hasAlpha;
setHasAlpha(other.m_hasAlpha);
}
const RGBA32Array& bytes() const { return m_bytes; }
RGBA32Array& bytes() { return m_bytes; }
// This function copies [(startX, startY), (endX, startY)) to the same
// X-coordinates on each subsequent row up to but not including endY.
//
// NOTE: This function does not sanity-check its arguments! Callers
// MUST not pass invalid values or this will corrupt memory.
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, endY), startAddr, rowBytes);
}
// Must be called before any pixels are written. Will return true on
// success, false if the memory allocation fails.
......@@ -91,31 +118,77 @@ namespace WebCore {
// NOTE: This has no way to check for allocation failure if the
// requested size was too big...
m_bytes.resize(width * height);
m_size = IntSize(width, height);
// Clear the image.
m_bytes.fill(0);
m_hasAlpha = true;
// Zero the image.
zeroFill();
return true;
}
// 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
{
return cairo_image_surface_create_for_data(
reinterpret_cast<unsigned char*>(const_cast<PixelData*>(
m_bytes.data())), CAIRO_FORMAT_ARGB32, width(), height(),
width() * sizeof(PixelData));
}
bool hasAlpha() const { return m_hasAlpha; }
const IntRect& rect() const { return m_rect; }
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) { m_hasAlpha = alpha; }
void setRect(const IntRect& r) { m_rect = r; }
void setStatus(FrameStatus s) { m_status = s; }
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:
// Initialize with another buffer. This function doesn't create a new copy
// of the image data, it only increases the refcount of the existing bitmap.
//
// Normal callers should not generally be using this function. If you want
// to create a copy on which you can modify the image data independently,
// use copyBitmapData() instead.
RGBA32Buffer& operator=(const RGBA32Buffer& other)
{
if (this == &other)
return *this;
m_bytes = other.m_bytes;
m_size = other.m_size;
setHasAlpha(other.hasAlpha());
setRect(other.rect());
setStatus(other.status());
setDuration(other.duration());
setDisposalMethod(other.disposalMethod());
return *this;
}
inline int width() const { return m_size.width(); }
inline int height() const { return m_size.height(); }
inline PixelData* getAddr(int x, int y)
{
return m_bytes.data() + (y * width()) + x;
}
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;
......@@ -123,19 +196,21 @@ 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.
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.
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
......
......@@ -321,10 +321,8 @@ bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
// Copy the whole previous buffer, then clear just its frame.
buffer->copyBitmapData(*prevBuffer);
for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {
unsigned* const currentRow =
buffer->bytes().data() + (y * size().width());
for (int x = prevRect.x(); x < prevRect.right(); ++x)
buffer->setRGBA(*(currentRow + x), 0, 0, 0, 0);
buffer->setRGBA(x, y, 0, 0, 0, 0);
}
if ((prevRect.width() > 0) && (prevRect.height() > 0))
buffer->setHasAlpha(true);
......@@ -341,47 +339,43 @@ bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
}
void GIFImageDecoder::haveDecodedRow(unsigned frameIndex,
unsigned char* rowBuffer, // Pointer to single scanline temporary buffer
unsigned char* rowBuffer,
unsigned char* rowEnd,
unsigned rowNumber, // The row index
unsigned repeatCount, // How many times to repeat the row
unsigned rowNumber,
unsigned repeatCount,
bool writeTransparentPixels)
{
// Initialize the frame if necessary.
RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
if ((buffer.status() == RGBA32Buffer::FrameEmpty) && !initFrameBuffer(frameIndex))
return;
// Do nothing for bogus data.
if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= size().height())
// The pixel data and coordinates supplied to us are relative to the frame's
// origin within the entire image size, i.e.
// (m_reader->frameXOffset(), m_reader->frameYOffset()).
int x = m_reader->frameXOffset();
const int y = m_reader->frameYOffset() + rowNumber;
// Sanity-check the arguments.
if ((rowBuffer == 0) || (y >= size().height()))
return;
// Get the colormap.
unsigned colorMapSize;
unsigned char* colorMap;
m_reader->getColorMap(colorMap, colorMapSize);
if (!colorMap)
return;
// The buffers that we draw are the entire image's width and height, so a final output frame is
// width * height RGBA32 values in size.
//
// A single GIF frame, however, can be smaller than the entire image, i.e., it can represent some sub-rectangle
// within the overall image. The rows we are decoding are within this
// sub-rectangle. This means that if the GIF frame's sub-rectangle is (x,y,w,h) then row 0 is really row
// y, and each row goes from x to x+w.
unsigned dstPos = (m_reader->frameYOffset() + rowNumber) * size().width() + m_reader->frameXOffset();
unsigned* dst = buffer.bytes().data() + dstPos;
unsigned* dstEnd = dst + size().width() - m_reader->frameXOffset();
unsigned* currDst = dst;
unsigned char* currentRowByte = rowBuffer;
while (currentRowByte != rowEnd && currDst < dstEnd) {
if ((!m_reader->isTransparent() || *currentRowByte != m_reader->transparentPixel()) && *currentRowByte < colorMapSize) {
unsigned colorIndex = *currentRowByte * 3;
unsigned red = colorMap[colorIndex];
unsigned green = colorMap[colorIndex + 1];
unsigned blue = colorMap[colorIndex + 2];
RGBA32Buffer::setRGBA(*currDst, red, green, blue, 255);
// Initialize the frame if necessary.
RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
if ((buffer.status() == RGBA32Buffer::FrameEmpty) && !initFrameBuffer(frameIndex))
return;
// Write one row's worth of data into the frame. There is no guarantee that
// (rowEnd - rowBuffer) == (size().width() - m_reader->frameXOffset()), so
// we must ensure we don't run off the end of either the source data or the
// row's X-coordinates.
for (unsigned char* sourceAddr = rowBuffer; (sourceAddr != rowEnd) && (x < size().width()); ++sourceAddr, ++x) {
const unsigned char sourceValue = *sourceAddr;
if ((!m_reader->isTransparent() || (sourceValue != m_reader->transparentPixel())) && (sourceValue < colorMapSize)) {
const size_t colorIndex = static_cast<size_t>(sourceValue) * 3;
buffer.setRGBA(x, y, colorMap[colorIndex], colorMap[colorIndex + 1], colorMap[colorIndex + 2], 255);
} else {
m_currentBufferSawAlpha = true;
// We may or may not need to write transparent pixels to the buffer.
......@@ -392,26 +386,13 @@ void GIFImageDecoder::haveDecodedRow(unsigned frameIndex,
// beyond the first, or the initial passes will "show through" the
// later ones.
if (writeTransparentPixels)
RGBA32Buffer::setRGBA(*currDst, 0, 0, 0, 0);
buffer.setRGBA(x, y, 0, 0, 0, 0);
}
currDst++;
currentRowByte++;
}
if (repeatCount > 1) {
// Copy the row |repeatCount|-1 times.
unsigned num = currDst - dst;
unsigned dataSize = num * sizeof(unsigned);
unsigned width = size().width();
unsigned* end = buffer.bytes().data() + width * size().height();
currDst = dst + width;
for (unsigned i = 1; i < repeatCount; i++) {
if (currDst + num > end) // Protect against a buffer overrun from a bogus repeatCount.
break;
memcpy(currDst, dst, dataSize);
currDst += width;
}
}
// Tell the frame to copy the row data if need be.
if (repeatCount > 1)
buffer.copyRowNTimes(m_reader->frameXOffset(), x, y, std::min(y + static_cast<int>(repeatCount), size().height()));
}
void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod)
......
......@@ -38,7 +38,7 @@
#include "config.h"
#include "JPEGImageDecoder.h"
#include <assert.h>
#include <stdio.h>
#include <stdio.h> // Needed by jpeglib.h for FILE.
extern "C" {
#include "jpeglib.h"
......@@ -475,8 +475,6 @@ bool JPEGImageDecoder::outputScanlines()
jpeg_decompress_struct* info = m_reader->info();
JSAMPARRAY samples = m_reader->samples();
unsigned* dst = buffer.bytes().data() + info->output_scanline * size().width();
while (info->output_scanline < info->output_height) {
/* Request one scanline. Returns 0 or 1 scanlines. */
if (jpeg_read_scanlines(info, samples, 1) != 1)
......@@ -486,7 +484,9 @@ bool JPEGImageDecoder::outputScanlines()
unsigned r = *j1++;
unsigned g = *j1++;
unsigned b = *j1++;
RGBA32Buffer::setRGBA(*dst++, r, g, b, 0xFF);
// read_scanlines has increased the scanline counter, so we
// actually mean the previous one.
buffer.setRGBA(x, info->output_scanline - 1, r, g, b, 0xFF);
}
}
......
......@@ -380,14 +380,13 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
// Copy the data into our buffer.
int width = size().width();
unsigned* dst = buffer.bytes().data() + rowIndex * width;
bool sawAlpha = false;
for (int x = 0; x < width; x++) {
unsigned red = *row++;
unsigned green = *row++;
unsigned blue = *row++;
unsigned alpha = (hasAlpha ? *row++ : 255);
RGBA32Buffer::setRGBA(*dst++, red, green, blue, alpha);
buffer.setRGBA(x, rowIndex, red, green, blue, alpha);
if (!sawAlpha && alpha < 255) {
sawAlpha = true;
buffer.setHasAlpha(true);
......
......@@ -45,7 +45,6 @@ namespace WebCore {
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.
......@@ -54,6 +53,7 @@ namespace WebCore {
DisposeOverwriteBgcolor, // Clear frame to transparent
DisposeOverwritePrevious, // Clear frame to previous framebuffer contents
};
typedef uint32_t PixelData;
RGBA32Buffer()
: m_status(FrameEmpty)
......@@ -64,37 +64,14 @@ namespace WebCore {
// This constructor doesn't create a new copy of the image data, it only
// increases the ref count of the existing bitmap.
//
// This exists because ImageDecoder keeps a Vector<RGBA32Buffer>, and
// Vector requires this constructor.
RGBA32Buffer(const RGBA32Buffer& other)
{
operator=(other);
}
~RGBA32Buffer()
{
}
// Initialize with another buffer. This function doesn't create a new copy
// of the image data, it only increases the refcount of the existing bitmap.
//
// Normal callers should not generally be using this function. If you want
// to create a copy on which you can modify the image data independently,
// use copyBitmapData() instead.
RGBA32Buffer& operator=(const RGBA32Buffer& other)
{
if (this == &other)
return *this;
m_bitmap = other.m_bitmap;
// Keep the pixels locked since we will be writing directly into the
// bitmap throughout this object's lifetime.
m_bitmap.lockPixels();
setRect(other.rect());
setStatus(other.status());
setDuration(other.duration());
setDisposalMethod(other.disposalMethod());
return *this;
}
void clear()
{
m_bitmap.reset();
......@@ -129,14 +106,14 @@ namespace WebCore {
// MUST not pass invalid values or this will corrupt memory.
void copyRowNTimes(int startX, int endX, int startY, int endY)
{
ASSERT(startX < m_bitmap.width());
ASSERT(endX <= m_bitmap.width());
ASSERT(startY < m_bitmap.height());
ASSERT(endY <= m_bitmap.height());
const int rowBytes = (endX - startX) * sizeof(uint32_t);
const uint32_t* const startAddr = m_bitmap.getAddr32(startX, startY);
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(m_bitmap.getAddr32(startX, destY), startAddr, rowBytes);
memcpy(getAddr(startX, startY), startAddr, rowBytes);
}
// Must be called before any pixels are written. Will return true on
......@@ -145,7 +122,7 @@ namespace WebCore {
{
// This function should only be called once, it will leak memory
// otherwise.
ASSERT(m_bitmap.width() == 0 && m_bitmap.height() == 0);
ASSERT(width() == 0 && height() == 0);
m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
if (!m_bitmap.allocPixels()) {
// Allocation failure, maybe the bitmap was too big.
......@@ -162,32 +139,66 @@ namespace WebCore {
// 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()
NativeImagePtr asNewNativeImage() const
{
return new NativeImageSkia(m_bitmap);
}
bool hasAlpha() const { return !m_bitmap.isOpaque(); }
const IntRect& rect() const { return m_rect; }
FrameStatus status() const { return m_status; }
unsigned duration() const { return m_duration; }
FrameDisposalMethod disposalMethod() const { return m_disposalMethod; }
bool hasAlpha() const { return !m_bitmap.isOpaque(); }
void setHasAlpha(bool alpha) { m_bitmap.setIsOpaque(!alpha); }
void setRect(const IntRect& r) { m_rect = r; }
void setStatus(FrameStatus s)
{
m_status = s;
if (s == FrameComplete)
m_bitmap.setDataComplete(); // Tell the bitmap it's done.
m_status = s;
}
void setDuration(unsigned duration) { m_duration = duration; }
void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; }
void setHasAlpha(bool alpha) { m_bitmap.setIsOpaque(!alpha); }
void setRGBA(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t 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:
// Initialize with another buffer. This function doesn't create a new copy
// of the image data, it only increases the refcount of the existing bitmap.
//
// Normal callers should not generally be using this function. If you want
// to create a copy on which you can modify the image data independently,
// use copyBitmapData() instead.
RGBA32Buffer& operator=(const RGBA32Buffer& other)
{
uint32_t* const dest = m_bitmap.getAddr32(x, y);
if (this == &other)
return *this;
m_bitmap = other.m_bitmap;
// Keep the pixels locked since we will be writing directly into the
// bitmap throughout this object's lifetime.
m_bitmap.lockPixels();
setRect(other.rect());
setStatus(other.status());
setDuration(other.duration());
setDisposalMethod(other.disposalMethod());
return *this;
}
inline int width() const { return m_bitmap.width(); }
inline int height() const { return m_bitmap.height(); }
inline PixelData* getAddr(int x, int y)
{
return m_bitmap.getAddr32(x, y);
}
inline void setRGBA(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a)
{
// We store this data pre-multiplied.
if (a == 0)
*dest = 0;
......@@ -202,14 +213,14 @@ namespace WebCore {
}
}
private:
NativeImageSkia m_bitmap;
IntRect<