diff options
-rw-r--r-- | gyp/tests.gyp | 1 | ||||
-rw-r--r-- | src/images/SkImageDecoder_libgif.cpp | 183 | ||||
-rw-r--r-- | tests/GifTest.cpp | 210 |
3 files changed, 324 insertions, 70 deletions
diff --git a/gyp/tests.gyp b/gyp/tests.gyp index 32f3abf7ef..daa6a8b736 100644 --- a/gyp/tests.gyp +++ b/gyp/tests.gyp @@ -64,6 +64,7 @@ '../tests/FontNamesTest.cpp', '../tests/FrontBufferedStreamTest.cpp', '../tests/GeometryTest.cpp', + '../tests/GifTest.cpp', '../tests/GLInterfaceValidation.cpp', '../tests/GLProgramsTest.cpp', '../tests/GpuBitmapCopyTest.cpp', diff --git a/src/images/SkImageDecoder_libgif.cpp b/src/images/SkImageDecoder_libgif.cpp index ab0fbdaf3f..f484441c8c 100644 --- a/src/images/SkImageDecoder_libgif.cpp +++ b/src/images/SkImageDecoder_libgif.cpp @@ -5,14 +5,15 @@ * found in the LICENSE file. */ - #include "SkColor.h" #include "SkColorPriv.h" #include "SkColorTable.h" #include "SkImageDecoder.h" +#include "SkRTConf.h" #include "SkScaledBitmapSampler.h" #include "SkStream.h" #include "SkTemplates.h" +#include "SkUtils.h" #include "gif_lib.h" @@ -36,6 +37,12 @@ static const uint8_t gDeltaIterlaceYValue[] = { 8, 8, 4, 2 }; +SK_CONF_DECLARE(bool, c_suppressGIFImageDecoderWarnings, + "images.gif.suppressDecoderWarnings", true, + "Suppress GIF warnings and errors when calling image decode " + "functions."); + + /* Implement the GIF interlace algorithm in an iterator. 1) grab every 8th line beginning at 0 2) grab every 8th line beginning at 4 @@ -145,14 +152,21 @@ static int find_transpIndex(const SavedImage& image, int colorCount) { return transpIndex; } -static bool error_return(GifFileType* gif, const SkBitmap& bm, - const char msg[]) { -#if 0 - SkDebugf("libgif error <%s> bitmap [%d %d] pixels %p colortable %p\n", - msg, bm.width(), bm.height(), bm.getPixels(), bm.getColorTable()); -#endif +static bool error_return(const SkBitmap& bm, const char msg[]) { + if (!c_suppressGIFImageDecoderWarnings) { + SkDebugf("libgif error [%s] bitmap [%d %d] pixels %p colortable %p\n", + msg, bm.width(), bm.height(), bm.getPixels(), + bm.getColorTable()); + } return false; } +static void gif_warning(const SkBitmap& bm, const char msg[]) { + if (!c_suppressGIFImageDecoderWarnings) { + SkDebugf("libgif warning [%s] bitmap [%d %d] pixels %p colortable %p\n", + msg, bm.width(), bm.height(), bm.getPixels(), + bm.getColorTable()); + } +} /** * Skip rows in the source gif image. @@ -178,7 +192,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc, NULL); #endif if (NULL == gif) { - return error_return(gif, *bm, "DGifOpen"); + return error_return(*bm, "DGifOpen"); } SkAutoTCallIProc<GifFileType, DGifCloseFile> acp(gif); @@ -195,31 +209,66 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { int extFunction; #endif int transpIndex = -1; // -1 means we don't have it (yet) + int fillIndex = gif->SBackGroundColor; do { if (DGifGetRecordType(gif, &recType) == GIF_ERROR) { - return error_return(gif, *bm, "DGifGetRecordType"); + return error_return(*bm, "DGifGetRecordType"); } switch (recType) { case IMAGE_DESC_RECORD_TYPE: { if (DGifGetImageDesc(gif) == GIF_ERROR) { - return error_return(gif, *bm, "IMAGE_DESC_RECORD_TYPE"); + return error_return(*bm, "IMAGE_DESC_RECORD_TYPE"); } if (gif->ImageCount < 1) { // sanity check - return error_return(gif, *bm, "ImageCount < 1"); + return error_return(*bm, "ImageCount < 1"); } width = gif->SWidth; height = gif->SHeight; - if (width <= 0 || height <= 0) { - return error_return(gif, *bm, "invalid dimensions"); + + SavedImage* image = &gif->SavedImages[gif->ImageCount-1]; + const GifImageDesc& desc = image->ImageDesc; + + int imageLeft = desc.Left; + int imageTop = desc.Top; + const int innerWidth = desc.Width; + const int innerHeight = desc.Height; + if (innerWidth <= 0 || innerHeight <= 0) { + return error_return(*bm, "invalid dimensions"); + } + + // check for valid descriptor + if (innerWidth > width) { + gif_warning(*bm, "image too wide, expanding output to size"); + width = innerWidth; + imageLeft = 0; + } else if (imageLeft + innerWidth > width) { + gif_warning(*bm, "shifting image left to fit"); + imageLeft = width - innerWidth; + } else if (imageLeft < 0) { + gif_warning(*bm, "shifting image right to fit"); + imageLeft = 0; + } + + + if (innerHeight > height) { + gif_warning(*bm, "image too tall, expanding output to size"); + height = innerHeight; + imageTop = 0; + } else if (imageTop + innerHeight > height) { + gif_warning(*bm, "shifting image up to fit"); + imageTop = height - innerHeight; + } else if (imageTop < 0) { + gif_warning(*bm, "shifting image down to fit"); + imageTop = 0; } // FIXME: We could give the caller a choice of images or configs. if (!this->chooseFromOneChoice(SkBitmap::kIndex8_Config, width, height)) { - return error_return(gif, *bm, "chooseFromOneChoice"); + return error_return(*bm, "chooseFromOneChoice"); } SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); @@ -231,58 +280,53 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { return true; } - SavedImage* image = &gif->SavedImages[gif->ImageCount-1]; - const GifImageDesc& desc = image->ImageDesc; - - // check for valid descriptor - if ( (desc.Top | desc.Left) < 0 || - desc.Left + desc.Width > width || - desc.Top + desc.Height > height) { - return error_return(gif, *bm, "TopLeft"); - } // now we decode the colortable int colorCount = 0; { - const ColorMapObject* cmap = find_colormap(gif); - if (NULL == cmap) { - return error_return(gif, *bm, "null cmap"); - } - colorCount = cmap->ColorCount; - if (colorCount > 256) { - colorCount = 256; // our kIndex8 can't support more - } - + // Declare colorPtr here for scope. SkPMColor colorPtr[256]; // storage for worst-case + const ColorMapObject* cmap = find_colormap(gif); SkAlphaType alphaType = kOpaque_SkAlphaType; - for (int index = 0; index < colorCount; index++) { - colorPtr[index] = SkPackARGB32(0xFF, - cmap->Colors[index].Red, - cmap->Colors[index].Green, - cmap->Colors[index].Blue); + if (cmap != NULL) { + colorCount = cmap->ColorCount; + if (colorCount > 256) { + colorCount = 256; // our kIndex8 can't support more + } + for (int index = 0; index < colorCount; index++) { + colorPtr[index] = SkPackARGB32(0xFF, + cmap->Colors[index].Red, + cmap->Colors[index].Green, + cmap->Colors[index].Blue); + } + } else { + // find_colormap() returned NULL. Some (rare, broken) + // GIFs don't have a color table, so we force one. + gif_warning(*bm, "missing colormap"); + colorCount = 256; + sk_memset32(colorPtr, SK_ColorWHITE, colorCount); } - transpIndex = find_transpIndex(temp_save, colorCount); - bool reallyHasAlpha = transpIndex >= 0; - if (reallyHasAlpha) { + if (transpIndex >= 0) { colorPtr[transpIndex] = SK_ColorTRANSPARENT; // ram in a transparent SkPMColor alphaType = kPremul_SkAlphaType; + fillIndex = transpIndex; + } else if (fillIndex >= colorCount) { + // gif->SBackGroundColor should be less than colorCount. + fillIndex = 0; // If not, fix it. } SkAutoTUnref<SkColorTable> ctable(SkNEW_ARGS(SkColorTable, (colorPtr, colorCount, alphaType))); if (!this->allocPixelRef(bm, ctable)) { - return error_return(gif, *bm, "allocPixelRef"); + return error_return(*bm, "allocPixelRef"); } } - const int innerWidth = desc.Width; - const int innerHeight = desc.Height; - // abort if either inner dimension is <= 0 if (innerWidth <= 0 || innerHeight <= 0) { - return error_return(gif, *bm, "non-pos inner width/height"); + return error_return(*bm, "non-pos inner width/height"); } SkAutoLockPixels alp(*bm); @@ -296,29 +340,18 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { SkBitmap subset; SkBitmap* workingBitmap; // are we only a subset of the total bounds? - if ((desc.Top | desc.Left) > 0 || + if ((imageTop | imageLeft) > 0 || innerWidth < width || innerHeight < height) { - int fill; - if (transpIndex >= 0) { - fill = transpIndex; - } else { - fill = gif->SBackGroundColor; - } - // check for valid fill index/color - if (static_cast<unsigned>(fill) >= - static_cast<unsigned>(colorCount)) { - fill = 0; - } // Fill the background. - memset(bm->getPixels(), fill, bm->getSize()); + memset(bm->getPixels(), fillIndex, bm->getSize()); // Create a subset of the bitmap. - SkIRect subsetRect(SkIRect::MakeXYWH(desc.Left / sampler.srcDX(), - desc.Top / sampler.srcDY(), + SkIRect subsetRect(SkIRect::MakeXYWH(imageLeft / sampler.srcDX(), + imageTop / sampler.srcDY(), innerWidth / sampler.srcDX(), innerHeight / sampler.srcDY())); if (!bm->extractSubset(&subset, subsetRect)) { - return error_return(gif, *bm, "Extract failed."); + return error_return(*bm, "Extract failed."); } // Update the sampler. We'll now be only sampling into the subset. sampler = SkScaledBitmapSampler(innerWidth, innerHeight, this->getSampleSize()); @@ -332,7 +365,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { SkAutoLockPixels alpWorking(*workingBitmap); if (!sampler.begin(workingBitmap, SkScaledBitmapSampler::kIndex, *this)) { - return error_return(gif, *bm, "Sampler failed to begin."); + return error_return(*bm, "Sampler failed to begin."); } // now decode each scanline @@ -340,9 +373,15 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { // Iterate over the height of the source data. The sampler will // take care of skipping unneeded rows. GifInterlaceIter iter(innerHeight); - for (int y = 0; y < innerHeight; y++){ + for (int y = 0; y < innerHeight; y++) { if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { - return error_return(gif, *bm, "interlace DGifGetLine"); + gif_warning(*bm, "interlace DGifGetLine"); + memset(scanline, fillIndex, innerWidth); + for (; y < innerHeight; y++) { + sampler.sampleInterlaced(scanline, iter.currY()); + iter.next(); + } + return true; } sampler.sampleInterlaced(scanline, iter.currY()); iter.next(); @@ -353,7 +392,12 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { skip_src_rows(gif, scanline, innerWidth, sampler.srcY0()); for (int y = 0; y < outHeight; y++) { if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { - return error_return(gif, *bm, "DGifGetLine"); + gif_warning(*bm, "DGifGetLine"); + memset(scanline, fillIndex, innerWidth); + for (; y < outHeight; y++) { + sampler.next(scanline); + } + return true; } // scanline now contains the raw data. Sample it. sampler.next(scanline); @@ -366,7 +410,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { SkASSERT(read <= innerHeight); skip_src_rows(gif, scanline, innerWidth, innerHeight - read); } - goto DONE; + return true; } break; case EXTENSION_RECORD_TYPE: @@ -376,7 +420,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { #else if (DGifGetExtension(gif, &extFunction, &extData) == GIF_ERROR) { #endif - return error_return(gif, *bm, "DGifGetExtension"); + return error_return(*bm, "DGifGetExtension"); } while (extData != NULL) { @@ -391,10 +435,10 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { extData[0], &extData[1]) == GIF_ERROR) { #endif - return error_return(gif, *bm, "AddExtensionBlock"); + return error_return(*bm, "AddExtensionBlock"); } if (DGifGetExtensionNext(gif, &extData) == GIF_ERROR) { - return error_return(gif, *bm, "DGifGetExtensionNext"); + return error_return(*bm, "DGifGetExtensionNext"); } #if GIFLIB_MAJOR < 5 temp_save.Function = 0; @@ -410,7 +454,6 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { } } while (recType != TERMINATE_RECORD_TYPE); -DONE: return true; } diff --git a/tests/GifTest.cpp b/tests/GifTest.cpp new file mode 100644 index 0000000000..5919b44d68 --- /dev/null +++ b/tests/GifTest.cpp @@ -0,0 +1,210 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// This tests out GIF decoder (SkImageDecoder_libgif.cpp) +// It is not used on these platforms: +#if (!defined(SK_BUILD_FOR_WIN32)) && \ + (!defined(SK_BUILD_FOR_IOS)) && \ + (!defined(SK_BUILD_FOR_MAC)) + +#include "SkBitmap.h" +#include "SkData.h" +#include "SkForceLinking.h" +#include "SkImageDecoder.h" +#include "SkImage.h" +#include "SkStream.h" +#include "Test.h" + +__SK_FORCE_IMAGE_DECODER_LINKING; + +namespace { + unsigned char gifData[] = { + 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x03, 0x00, + 0x03, 0x00, 0xe3, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x80, 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x04, + 0x07, 0x50, 0x1c, 0x43, 0x40, 0x41, 0x23, 0x44, + 0x00, 0x3b}; + unsigned char gifDataNoColormap[] = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, + 0x01, 0x0a, 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, + 0x02, 0x4c, 0x01, 0x00, 0x3b}; + unsigned char interlacedGif[] = { + 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x09, 0x00, + 0x09, 0x00, 0xe3, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x80, 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0x40, 0x04, + 0x1b, 0x50, 0x1c, 0x23, 0xe9, 0x44, 0x23, 0x60, + 0x9d, 0x09, 0x28, 0x1e, 0xf8, 0x6d, 0x64, 0x56, + 0x9d, 0x53, 0xa8, 0x7e, 0xa8, 0x65, 0x94, 0x5c, + 0xb0, 0x8a, 0x45, 0x04, 0x00, 0x3b}; +}; // namespace + +static void test_gif_data_no_colormap(skiatest::Reporter* r, + void* data, size_t size) { + SkBitmap bm; + bool imageDecodeSuccess = SkImageDecoder::DecodeMemory( + data, size, &bm); + REPORTER_ASSERT(r, imageDecodeSuccess); + REPORTER_ASSERT(r, bm.width() == 1); + REPORTER_ASSERT(r, bm.height() == 1); + REPORTER_ASSERT(r, !(bm.empty())); + if (!(bm.empty())) { + REPORTER_ASSERT(r, bm.getColor(0, 0) == 0x00000000); + } +} +static void test_gif_data(skiatest::Reporter* r, void* data, size_t size) { + SkBitmap bm; + bool imageDecodeSuccess = SkImageDecoder::DecodeMemory( + data, size, &bm); + REPORTER_ASSERT(r, imageDecodeSuccess); + REPORTER_ASSERT(r, bm.width() == 3); + REPORTER_ASSERT(r, bm.height() == 3); + REPORTER_ASSERT(r, !(bm.empty())); + if (!(bm.empty())) { + REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000); + REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00); + REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff); + REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080); + REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000); + REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00); + REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff); + REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff); + REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff); + } +} +static void test_interlaced_gif_data(skiatest::Reporter* r, + void* data, + size_t size) { + SkBitmap bm; + bool imageDecodeSuccess = SkImageDecoder::DecodeMemory( + data, size, &bm); + REPORTER_ASSERT(r, imageDecodeSuccess); + REPORTER_ASSERT(r, bm.width() == 9); + REPORTER_ASSERT(r, bm.height() == 9); + REPORTER_ASSERT(r, !(bm.empty())); + if (!(bm.empty())) { + REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000); + REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00); + REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff); + + REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff); + REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff); + REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff); + + REPORTER_ASSERT(r, bm.getColor(0, 4) == 0xff808080); + REPORTER_ASSERT(r, bm.getColor(1, 4) == 0xff000000); + REPORTER_ASSERT(r, bm.getColor(2, 4) == 0xff00ff00); + + REPORTER_ASSERT(r, bm.getColor(0, 6) == 0xffff0000); + REPORTER_ASSERT(r, bm.getColor(1, 6) == 0xffffff00); + REPORTER_ASSERT(r, bm.getColor(2, 6) == 0xff00ffff); + + REPORTER_ASSERT(r, bm.getColor(0, 8) == 0xffffffff); + REPORTER_ASSERT(r, bm.getColor(1, 8) == 0xffff00ff); + REPORTER_ASSERT(r, bm.getColor(2, 8) == 0xff0000ff); + } +} + +static void test_gif_data_short(skiatest::Reporter* r, + void* data, + size_t size) { + SkBitmap bm; + bool imageDecodeSuccess = SkImageDecoder::DecodeMemory( + data, size, &bm); + REPORTER_ASSERT(r, imageDecodeSuccess); + REPORTER_ASSERT(r, bm.width() == 3); + REPORTER_ASSERT(r, bm.height() == 3); + REPORTER_ASSERT(r, !(bm.empty())); + if (!(bm.empty())) { + REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000); + REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00); + REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff); + REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080); + REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000); + REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00); + } +} + +/** + This test will test the ability of the SkImageDecoder to deal with + GIF files which have been mangled somehow. We want to display as + much of the GIF as possible. +*/ +static void TestGif(skiatest::Reporter* reporter) { + // test perfectly good images. + test_gif_data(reporter, static_cast<void *>(gifData), sizeof(gifData)); + test_interlaced_gif_data(reporter, static_cast<void *>(interlacedGif), + sizeof(interlacedGif)); + + unsigned char badData[sizeof(gifData)]; + + /* If you set the environment variable + skia_images_gif_suppressDecoderWarnings to 'false', you will + see warnings on stderr. This is a feature. */ + + memcpy(badData, gifData, sizeof(gifData)); + badData[6] = 0x01; // image too wide + test_gif_data(reporter, static_cast<void *>(badData), sizeof(gifData)); + // "libgif warning [image too wide, expanding output to size]" + + memcpy(badData, gifData, sizeof(gifData)); + badData[8] = 0x01; // image too tall + test_gif_data(reporter, static_cast<void *>(badData), sizeof(gifData)); + // "libgif warning [image too tall, expanding output to size]" + + memcpy(badData, gifData, sizeof(gifData)); + badData[62] = 0x01; // image shifted right + test_gif_data(reporter, static_cast<void *>(badData), sizeof(gifData)); + // "libgif warning [shifting image left to fit]" + + memcpy(badData, gifData, sizeof(gifData)); + badData[64] = 0x01; // image shifted down + test_gif_data(reporter, static_cast<void *>(badData), sizeof(gifData)); + // "libgif warning [shifting image up to fit]" + + memcpy(badData, gifData, sizeof(gifData)); + badData[62] = 0xff; // image shifted left + badData[63] = 0xff; // 2's complement -1 short + test_gif_data(reporter, static_cast<void *>(badData), sizeof(gifData)); + // "libgif warning [shifting image left to fit]" + + memcpy(badData, gifData, sizeof(gifData)); + badData[64] = 0xff; // image shifted up + badData[65] = 0xff; // 2's complement -1 short + test_gif_data(reporter, static_cast<void *>(badData), sizeof(gifData)); + // "libgif warning [shifting image up to fit]" + + test_gif_data_no_colormap(reporter, static_cast<void *>(gifDataNoColormap), + sizeof(gifDataNoColormap)); + // "libgif warning [missing colormap]" + + // test short Gif. 80 is missing a few bytes. + test_gif_data_short(reporter, static_cast<void *>(gifData), 80); + // "libgif warning [DGifGetLine]" + + test_interlaced_gif_data(reporter, static_cast<void *>(interlacedGif), + 100); // 100 is missing a few bytes + // "libgif warning [interlace DGifGetLine]" +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("GifTest", GifTestClass, TestGif) + +#endif // !(SK_BUILD_FOR_WIN32||SK_BUILD_FOR_IOS||SK_BUILD_FOR_MAC) |