summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Reed <>2009-03-24 22:30:39 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-24 22:30:39 -0700
commit6d20683c4bff963e2e8ca340cd968db81a9b81ec (patch)
tree9dd4d9df57aa09c4f95e1191b0d519ea7a9de928
parent145f9f956cb5adf1c9f165e7376644e0cadd6792 (diff)
downloadexternal_webkit-6d20683c4bff963e2e8ca340cd968db81a9b81ec.zip
external_webkit-6d20683c4bff963e2e8ca340cd968db81a9b81ec.tar.gz
external_webkit-6d20683c4bff963e2e8ca340cd968db81a9b81ec.tar.bz2
Automated import from //branches/donutburger/...@142335,142335
-rw-r--r--Android.mk1
-rw-r--r--WebCore/Android.mk6
-rw-r--r--WebCore/WebCorePrefixAndroid.h3
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp4
-rw-r--r--WebCore/platform/graphics/ImageSource.h6
-rw-r--r--WebCore/platform/graphics/android/ImageAndroid.cpp21
-rw-r--r--WebCore/platform/graphics/android/ImageSourceAndroid.cpp148
-rw-r--r--WebCore/platform/graphics/skia/NativeImageSkia.cpp5
-rw-r--r--WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp55
-rw-r--r--WebCore/platform/image-decoders/skia/ImageDecoder.h10
10 files changed, 224 insertions, 35 deletions
diff --git a/Android.mk b/Android.mk
index cc2b51f..ef65a62 100644
--- a/Android.mk
+++ b/Android.mk
@@ -121,6 +121,7 @@ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/WebCore/platform/graphics \
$(LOCAL_PATH)/WebCore/platform/graphics/android \
$(LOCAL_PATH)/WebCore/platform/graphics/network \
+ $(LOCAL_PATH)/WebCore/platform/graphics/skia \
$(LOCAL_PATH)/WebCore/platform/graphics/transforms \
$(LOCAL_PATH)/WebCore/platform/image-decoders \
$(LOCAL_PATH)/WebCore/platform/network \
diff --git a/WebCore/Android.mk b/WebCore/Android.mk
index 5b0880e..7b909e3 100644
--- a/WebCore/Android.mk
+++ b/WebCore/Android.mk
@@ -651,6 +651,8 @@ LOCAL_SRC_FILES := \
\
platform/graphics/WidthIterator.cpp \
\
+ platform/graphics/skia/NativeImageSkia.cpp \
+ \
platform/graphics/transforms/MatrixTransformOperation.cpp \
platform/graphics/transforms/RotateTransformOperation.cpp \
platform/graphics/transforms/ScaleTransformOperation.cpp \
@@ -658,6 +660,10 @@ LOCAL_SRC_FILES := \
platform/graphics/transforms/TransformOperations.cpp \
platform/graphics/transforms/TransformationMatrix.cpp \
platform/graphics/transforms/TranslateTransformOperation.cpp \
+ \
+ platform/image-decoders/skia/GIFImageDecoder.cpp \
+ platform/image-decoders/skia/GIFImageReader.cpp \
+ \
platform/network/AuthenticationChallengeBase.cpp \
platform/network/Credential.cpp \
platform/network/FormData.cpp \
diff --git a/WebCore/WebCorePrefixAndroid.h b/WebCore/WebCorePrefixAndroid.h
index d69c122..e1f0650 100644
--- a/WebCore/WebCorePrefixAndroid.h
+++ b/WebCore/WebCorePrefixAndroid.h
@@ -162,3 +162,6 @@ typedef unsigned char flex_uint8_t;
// needs additional flavor or parameter to know that it can't be ignored,
// and/or script engine must keep whether event was user initiated.
#define ANDROID_SCROLL_ON_GOTO_ANCHOR
+
+// Animated GIF support.
+#define ANDROID_ANIMATED_GIF
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
index 45b32ab..68863df 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -262,6 +262,10 @@ bool BitmapImage::shouldAnimate()
void BitmapImage::startAnimation(bool catchUpIfNecessary)
{
+#ifdef ANDROID_ANIMATED_GIF
+ // We can't ever seem to keep up, so always let us just show the next frame
+ catchUpIfNecessary = false;
+#endif
if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
return;
diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h
index 55e0c5a..07cc2c2 100644
--- a/WebCore/platform/graphics/ImageSource.h
+++ b/WebCore/platform/graphics/ImageSource.h
@@ -71,9 +71,15 @@ typedef ImageDecoderQt* NativeImageSourcePtr;
typedef QPixmap* NativeImagePtr;
#elif PLATFORM(SGL)
class String;
+#ifdef ANDROID_ANIMATED_GIF
+class ImageDecoder;
+#endif
struct NativeImageSourcePtr {
SkString m_url;
PrivateAndroidImageSourceRec* m_image;
+#ifdef ANDROID_ANIMATED_GIF
+ ImageDecoder* m_gifDecoder;
+#endif
};
typedef const Vector<char>* NativeBytePtr;
typedef SkBitmapRef* NativeImagePtr;
diff --git a/WebCore/platform/graphics/android/ImageAndroid.cpp b/WebCore/platform/graphics/android/ImageAndroid.cpp
index da52d67..3a3312f 100644
--- a/WebCore/platform/graphics/android/ImageAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageAndroid.cpp
@@ -67,8 +67,6 @@ bool FrameData::clear(bool clearMetadata)
if (m_frame) {
m_frame->unref();
m_frame = 0;
- m_duration = 0.;
- m_hasAlpha = true;
return true;
}
return false;
@@ -157,11 +155,16 @@ void BitmapImage::checkForSolidColor()
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
const FloatRect& srcRect, CompositeOperator compositeOp)
{
+ if (!m_source.initialized())
+ return;
+
+ startAnimation();
+
SkBitmapRef* image = this->nativeImageForCurrentFrame();
if (!image) { // If it's too early we won't have an image yet.
return;
}
-
+
// in case we get called with an incomplete bitmap
const SkBitmap& bitmap = image->bitmap();
if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
@@ -172,12 +175,12 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
#endif
return;
}
-
+
SkIRect srcR;
SkRect dstR;
float invScaleX = (float)bitmap.width() / image->origWidth();
float invScaleY = (float)bitmap.height() / image->origHeight();
-
+
android_setrect(&dstR, dstRect);
android_setrect_scaled(&srcR, srcRect, invScaleX, invScaleY);
if (srcR.isEmpty() || dstR.isEmpty()) {
@@ -188,16 +191,14 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
#endif
return;
}
-
+
SkCanvas* canvas = ctxt->platformContext()->mCanvas;
SkPaint paint;
-
+
paint.setFilterBitmap(true);
paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);
-
- startAnimation();
-
+
#ifdef TRACE_SUBSAMPLED_BITMAPS
if (bitmap.width() != image->origWidth() ||
bitmap.height() != image->origHeight()) {
diff --git a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
index 4bf8f8e..4c6a246 100644
--- a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
@@ -25,7 +25,6 @@
#include "config.h"
#include "BitmapAllocatorAndroid.h"
-#include "ImageDecoder.h"
#include "ImageSource.h"
#include "IntSize.h"
#include "NotImplemented.h"
@@ -33,11 +32,18 @@
#include "PlatformString.h"
#include "SkBitmapRef.h"
-#include "SkImageRef.h"
#include "SkImageDecoder.h"
+#include "SkImageRef.h"
#include "SkStream.h"
#include "SkTemplates.h"
+#ifdef ANDROID_ANIMATED_GIF
+ #include "EmojiFont.h"
+ #include "skia/GIFImageDecoder.h"
+
+ using namespace android;
+#endif
+
SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src);
//#define TRACE_SUBSAMPLE_BITMAPS
@@ -95,14 +101,24 @@ namespace WebCore {
ImageSource::ImageSource() {
m_decoder.m_image = NULL;
+#ifdef ANDROID_ANIMATED_GIF
+ m_decoder.m_gifDecoder = 0;
+#endif
}
ImageSource::~ImageSource() {
delete m_decoder.m_image;
+#ifdef ANDROID_ANIMATED_GIF
+ delete m_decoder.m_gifDecoder;
+#endif
}
bool ImageSource::initialized() const {
- return m_decoder.m_image != NULL;
+ return
+#ifdef ANDROID_ANIMATED_GIF
+ m_decoder.m_gifDecoder ||
+#endif
+ m_decoder.m_image != NULL;
}
static int computeSampleSize(const SkBitmap& bitmap) {
@@ -164,11 +180,32 @@ void ImageSource::setURL(const String& url)
}
}
+#ifdef ANDROID_ANIMATED_GIF
+// we only animate small GIFs for now, to save memory
+// also, we only support this in Japan, hence the Emoji check
+static bool should_use_animated_gif(int width, int height) {
+ return EmojiFont::IsAvailable() &&
+ width <= 32 && height <= 32;
+}
+#endif
+
void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
{
- if (NULL == m_decoder.m_image) {
+#ifdef ANDROID_ANIMATED_GIF
+ // This is only necessary if we allow ourselves to partially decode GIF
+ if (m_decoder.m_gifDecoder
+ && !m_decoder.m_gifDecoder->failed()) {
+ m_decoder.m_gifDecoder->setData(data, allDataReceived);
+ return;
+ }
+#endif
+ if (NULL == m_decoder.m_image
+#ifdef ANDROID_ANIMATED_GIF
+ && !m_decoder.m_gifDecoder
+#endif
+ ) {
SkBitmap tmp;
-
+
SkMemoryStream stream(data->data(), data->size(), false);
SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
SkAutoTDelete<SkImageDecoder> ad(codec);
@@ -180,6 +217,25 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
int origW = tmp.width();
int origH = tmp.height();
+
+#ifdef ANDROID_ANIMATED_GIF
+ // First, check to see if this is an animated GIF
+ const Vector<char>& buffer = data->buffer();
+ const char* contents = buffer.data();
+ if (buffer.size() > 3 && strncmp(contents, "GIF8", 4) == 0 &&
+ should_use_animated_gif(origW, origH)) {
+ // This means we are looking at a GIF, so create special
+ // GIF Decoder
+ // Need to wait for all data received if we are assigning an
+ // allocator (which we are not at the moment).
+ if (!m_decoder.m_gifDecoder /*&& allDataReceived*/)
+ m_decoder.m_gifDecoder = new GIFImageDecoder();
+ if (!m_decoder.m_gifDecoder->failed())
+ m_decoder.m_gifDecoder->setData(data, allDataReceived);
+ return;
+ }
+#endif
+
int sampleSize = computeSampleSize(tmp);
if (sampleSize > 1) {
codec->setSampleSize(sampleSize);
@@ -222,11 +278,20 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
bool ImageSource::isSizeAvailable()
{
- return m_decoder.m_image != NULL;
+ return
+#ifdef ANDROID_ANIMATED_GIF
+ (m_decoder.m_gifDecoder
+ && m_decoder.m_gifDecoder->isSizeAvailable()) ||
+#endif
+ m_decoder.m_image != NULL;
}
IntSize ImageSource::size() const
{
+#ifdef ANDROID_ANIMATED_GIF
+ if (m_decoder.m_gifDecoder)
+ return m_decoder.m_gifDecoder->size();
+#endif
if (m_decoder.m_image) {
return IntSize(m_decoder.m_image->origWidth(), m_decoder.m_image->origHeight());
}
@@ -235,19 +300,40 @@ IntSize ImageSource::size() const
int ImageSource::repetitionCount()
{
+#ifdef ANDROID_ANIMATED_GIF
+ if (m_decoder.m_gifDecoder)
+ return m_decoder.m_gifDecoder->repetitionCount();
+ if (!m_decoder.m_image) return 0;
+#endif
return 1;
// A property with value 0 means loop forever.
}
size_t ImageSource::frameCount() const
{
+#ifdef ANDROID_ANIMATED_GIF
+ if (m_decoder.m_gifDecoder) {
+ return m_decoder.m_gifDecoder->failed() ? 0
+ : m_decoder.m_gifDecoder->frameCount();
+ }
+#endif
// i.e. 0 frames if we're not decoded, or 1 frame if we are
return m_decoder.m_image != NULL;
}
SkBitmapRef* ImageSource::createFrameAtIndex(size_t index)
{
+#ifdef ANDROID_ANIMATED_GIF
+ if (m_decoder.m_gifDecoder) {
+ RGBA32Buffer* buffer =
+ m_decoder.m_gifDecoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ return 0;
+ return new SkBitmapRef(buffer->bitmap());
+ }
+#else
SkASSERT(index == 0);
+#endif
SkASSERT(m_decoder.m_image != NULL);
m_decoder.m_image->ref();
return m_decoder.m_image;
@@ -255,8 +341,18 @@ SkBitmapRef* ImageSource::createFrameAtIndex(size_t index)
float ImageSource::frameDurationAtIndex(size_t index)
{
- SkASSERT(index == 0);
float duration = 0;
+#ifdef ANDROID_ANIMATED_GIF
+ if (m_decoder.m_gifDecoder) {
+ RGBA32Buffer* buffer
+ = m_decoder.m_gifDecoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ return 0;
+ duration = buffer->duration() / 1000.0f;
+ }
+#else
+ SkASSERT(index == 0);
+#endif
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
// We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
@@ -268,7 +364,21 @@ float ImageSource::frameDurationAtIndex(size_t index)
bool ImageSource::frameHasAlphaAtIndex(size_t index)
{
+#ifdef ANDROID_ANIMATED_GIF
+ if (m_decoder.m_gifDecoder) {
+ if (!m_decoder.m_gifDecoder->supportsAlpha())
+ return false;
+
+ RGBA32Buffer* buffer =
+ m_decoder.m_gifDecoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ return false;
+
+ return buffer->hasAlpha();
+ }
+#else
SkASSERT(0 == index);
+#endif
if (NULL == m_decoder.m_image)
return true; // if we're not sure, assume the worse-case
@@ -285,12 +395,32 @@ bool ImageSource::frameHasAlphaAtIndex(size_t index)
bool ImageSource::frameIsCompleteAtIndex(size_t index)
{
+#ifdef ANDROID_ANIMATED_GIF
+ if (m_decoder.m_gifDecoder) {
+ RGBA32Buffer* buffer =
+ m_decoder.m_gifDecoder->frameBufferAtIndex(index);
+ return buffer && buffer->status() == RGBA32Buffer::FrameComplete;
+ }
+#else
SkASSERT(0 == index);
+#endif
return m_decoder.m_image && m_decoder.m_image->fAllDataReceived;
}
void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
{
+#ifdef ANDROID_ANIMATED_GIF
+ if (!destroyAll) {
+ if (m_decoder.m_gifDecoder)
+ m_decoder.m_gifDecoder->clearFrameBufferCache(clearBeforeFrame);
+ return;
+ }
+
+ delete m_decoder.m_gifDecoder;
+ m_decoder.m_gifDecoder = 0;
+ if (data)
+ setData(data, allDataReceived);
+#endif
// do nothing, since the cache is managed elsewhere
}
@@ -303,6 +433,10 @@ IntSize ImageSource::frameSizeAtIndex(size_t index) const
String ImageSource::filenameExtension() const
{
// FIXME: need to add virtual to our decoders to return "jpg/png/gif/..."
+#ifdef ANDROID_ANIMATED_GIF
+ if (m_decoder.m_gifDecoder)
+ return m_decoder.m_gifDecoder->filenameExtension();
+#endif
return String();
}
diff --git a/WebCore/platform/graphics/skia/NativeImageSkia.cpp b/WebCore/platform/graphics/skia/NativeImageSkia.cpp
index e59d1e2..477be05 100644
--- a/WebCore/platform/graphics/skia/NativeImageSkia.cpp
+++ b/WebCore/platform/graphics/skia/NativeImageSkia.cpp
@@ -30,7 +30,9 @@
#include "config.h"
+#if PLATFORM(SKIA)
#include "skia/ext/image_operations.h"
+#endif
#include "NativeImageSkia.h"
#include "SkiaUtils.h"
@@ -63,9 +65,10 @@ bool NativeImageSkia::hasResizedBitmap(int w, int h) const
SkBitmap NativeImageSkia::resizedBitmap(int w, int h) const
{
+#if PLATFORM(SKIA)
if (m_resizedImage.width() != w || m_resizedImage.height() != h)
m_resizedImage = skia::ImageOperations::Resize(*this, skia::ImageOperations::RESIZE_LANCZOS3, w, h);
-
+#endif
return m_resizedImage;
}
diff --git a/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp
index 38bfa97..2d77943 100644
--- a/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp
@@ -193,6 +193,7 @@ void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
// can be asked to clear more frames than we currently have.
if (m_frameBufferCache.isEmpty())
return; // Nothing to do.
+
// The "-1" here is tricky. It does not mean that |clearBeforeFrame| is the
// last frame we wish to preserve, but rather that we never want to clear
// the very last frame in the cache: it's empty (so clearing it is
@@ -203,21 +204,36 @@ void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
// this case.
clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1);
const Vector<RGBA32Buffer>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame);
- for (Vector<RGBA32Buffer>::iterator i(m_frameBufferCache.begin()); i != end; ++i) {
- if (i->status() == RGBA32Buffer::FrameEmpty)
- continue; // Nothing to do.
-
- // The layout of frames is:
- // [empty frames][complete frames][partial frame][empty frames]
- // ...where each of these groups may be empty. We should not clear a
- // partial frame since that's what's being decoded right now, and we
- // also should not clear the last complete frame, since it may be needed
- // when constructing the next frame. Note that "i + 1" is safe since
- // i < end < m_frameBufferCache.end().
- if ((i->status() == RGBA32Buffer::FramePartial) || ((i + 1)->status() != RGBA32Buffer::FrameComplete))
- break;
-
- i->clear();
+
+ // We need to preserve frames such that:
+ // * We don't clear |end|
+ // * We don't clear the frame we're currently decoding
+ // * We don't clear any frame from which a future initFrameBuffer() call
+ // will copy bitmap data
+ // All other frames can be cleared. Because of the constraints on when
+ // ImageSource::clear() can be called (see ImageSource.h), we're guaranteed
+ // not to have non-empty frames after the frame we're currently decoding.
+ // So, scan backwards from |end| as follows:
+ // * If the frame is empty, we're still past any frames we care about.
+ // * If the frame is complete, but is DisposeOverwritePrevious, we'll
+ // skip over it in future initFrameBuffer() calls. We can clear it
+ // unless it's |end|, and keep scanning. For any other disposal method,
+ // stop scanning, as we've found the frame initFrameBuffer() will need
+ // next.
+ // * If the frame is partial, we're decoding it, so don't clear it; if it
+ // has a disposal method other than DisposeOverwritePrevious, stop
+ // scanning, as we'll only need this frame when decoding the next one.
+ Vector<RGBA32Buffer>::iterator i(end);
+ for (; (i != m_frameBufferCache.begin()) && ((i->status() == RGBA32Buffer::FrameEmpty) || (i->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious)); --i) {
+ if ((i->status() == RGBA32Buffer::FrameComplete) && (i != end))
+ i->clear();
+ }
+
+ // Now |i| holds the last frame we need to preserve; clear prior frames.
+ for (Vector<RGBA32Buffer>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
+ ASSERT(j->status() != RGBA32Buffer::FramePartial);
+ if (j->status() != RGBA32Buffer::FrameEmpty)
+ j->clear();
}
}
@@ -278,7 +294,6 @@ bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
// first frame specifies this method, it will get treated like
// DisposeOverwriteBgcolor below and reset to a completely empty image.)
const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];
- ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete);
RGBA32Buffer::FrameDisposalMethod prevMethod =
prevBuffer->disposalMethod();
while ((frameIndex > 0)
@@ -286,6 +301,7 @@ bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
prevBuffer = &m_frameBufferCache[--frameIndex];
prevMethod = prevBuffer->disposalMethod();
}
+ ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete);
if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) ||
(prevMethod == RGBA32Buffer::DisposeKeep)) {
@@ -310,6 +326,9 @@ bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
// Unnecessary (but safe); see comments on the similar call above.
buffer->setHasAlpha(prevBuffer->hasAlpha());
SkBitmap& bitmap = buffer->bitmap();
+#ifdef ANDROID_ANIMATED_GIF
+ SkAutoLockPixels alp(bitmap);
+#endif
for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {
for (int x = prevRect.x(); x < prevRect.right(); ++x)
buffer->setRGBA(bitmap.getAddr32(x, y), 0, 0, 0, 0);
@@ -361,6 +380,10 @@ void GIFImageDecoder::haveDecodedRow(unsigned frameIndex,
if (!colorMap)
return;
+#ifdef ANDROID_ANIMATED_GIF
+ // Lock the pixels properly. Should be submitted back to webkit.
+ SkAutoLockPixels alp(buffer.bitmap());
+#endif
// 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.
//
diff --git a/WebCore/platform/image-decoders/skia/ImageDecoder.h b/WebCore/platform/image-decoders/skia/ImageDecoder.h
index 9988a3e..b983315 100644
--- a/WebCore/platform/image-decoders/skia/ImageDecoder.h
+++ b/WebCore/platform/image-decoders/skia/ImageDecoder.h
@@ -39,6 +39,9 @@
#include <wtf/Vector.h>
#include "SkBitmap.h"
+#ifdef ANDROID_ANIMATED_GIF
+#include "SkColor.h"
+#endif
namespace WebCore {
@@ -169,7 +172,7 @@ namespace WebCore {
bmp.setConfig(SkBitmap::kARGB_8888_Config, width, height);
if (!bmp.allocPixels())
return false; // Allocation failure, maybe the bitmap was too big.
-
+
// Clear the image.
bmp.eraseARGB(0, 0, 0, 0);
@@ -199,6 +202,10 @@ namespace WebCore {
static void setRGBA(uint32_t* dest, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
// We store this data pre-multiplied.
+#ifdef ANDROID_ANIMATED_GIF
+ // Chrome should take this change as well.
+ *dest = SkPreMultiplyARGB(a, r, g, b);
+#else
if (a == 0)
*dest = 0;
else {
@@ -210,6 +217,7 @@ namespace WebCore {
}
*dest = (a << 24 | r << 16 | g << 8 | b);
}
+#endif
}
void setRGBA(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)