Index: src/images/SkImageDecoder_libgif.cpp |
diff --git a/src/images/SkImageDecoder_libgif.cpp b/src/images/SkImageDecoder_libgif.cpp |
index f484441c8c3e340d938582eff80c481b538cbf18..a045c27e160799228f1f92dbe0ad791cd179d7e0 100644 |
--- a/src/images/SkImageDecoder_libgif.cpp |
+++ b/src/images/SkImageDecoder_libgif.cpp |
@@ -185,6 +185,49 @@ static bool skip_src_rows(GifFileType* gif, uint8_t* dst, int width, int rowsToS |
return true; |
} |
+/** |
+ * GIFs with fewer then 256 color entries will sometimes index out of |
+ * bounds of the color table (this is malformed, but libgif does not |
+ * check sicne it is rare). This function checks for this error and |
+ * fixes it. This makes the output image consistantly deterministic. |
+ */ |
+static void sanitize_indexed_bitmap(SkBitmap* bm) { |
+ if ((SkBitmap::kIndex8_Config == bm->config()) && !(bm->empty())) { |
+ SkAutoLockPixels alp(*bm); |
+ if (NULL != bm->getPixels()) { |
+ SkColorTable* ct = bm->getColorTable(); // Index8 must have it. |
+ SkASSERT(ct != NULL); |
+ uint32_t count = ct->count(); |
+ SkASSERT(count > 0); |
+ SkASSERT(count <= 0x100); |
+ if (count != 0x100) { // Full colortables can't go wrong. |
+ // Count is a power of 2; asserted elsewhere. |
+ uint8_t byteMask = (~(count - 1)); |
+ bool warning = false; |
+ uint8_t* addr = static_cast<uint8_t*>(bm->getPixels()); |
+ int height = bm->height(); |
+ int width = bm->width(); |
+ size_t rowBytes = bm->rowBytes(); |
+ while (--height >= 0) { |
+ uint8_t* ptr = addr; |
+ int x = width; |
+ while (--x >= 0) { |
+ if (0 != ((*ptr) & byteMask)) { |
+ warning = true; |
+ *ptr = 0; |
+ } |
+ ++ptr; |
+ } |
+ addr += rowBytes; |
+ } |
+ if (warning) { |
+ gif_warning(*bm, "Index out of bounds."); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { |
#if GIFLIB_MAJOR < 5 |
GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc); |
@@ -289,6 +332,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { |
const ColorMapObject* cmap = find_colormap(gif); |
SkAlphaType alphaType = kOpaque_SkAlphaType; |
if (cmap != NULL) { |
+ SkASSERT(cmap->ColorCount == (1 << (cmap->BitsPerPixel))); |
colorCount = cmap->ColorCount; |
if (colorCount > 256) { |
colorCount = 256; // our kIndex8 can't support more |
@@ -410,6 +454,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { |
SkASSERT(read <= innerHeight); |
skip_src_rows(gif, scanline, innerWidth, innerHeight - read); |
} |
+ sanitize_indexed_bitmap(bm); |
return true; |
} break; |
@@ -454,6 +499,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { |
} |
} while (recType != TERMINATE_RECORD_TYPE); |
+ sanitize_indexed_bitmap(bm); |
return true; |
} |