Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 
     33 #include "platform/image-decoders/gif/GIFImageDecoder.h"
     34 
     35 #include "platform/SharedBuffer.h"
     36 #include "public/platform/Platform.h"
     37 #include "public/platform/WebData.h"
     38 #include "public/platform/WebSize.h"
     39 #include "public/platform/WebUnitTestSupport.h"
     40 #include "wtf/OwnPtr.h"
     41 #include "wtf/PassOwnPtr.h"
     42 #include "wtf/StringHasher.h"
     43 #include "wtf/Vector.h"
     44 #include <gtest/gtest.h>
     45 
     46 using namespace WebCore;
     47 using namespace blink;
     48 
     49 namespace {
     50 
     51 PassRefPtr<SharedBuffer> readFile(const char* fileName)
     52 {
     53     String filePath = Platform::current()->unitTestSupport()->webKitRootDir();
     54     filePath.append(fileName);
     55 
     56     return Platform::current()->unitTestSupport()->readFromFile(filePath);
     57 }
     58 
     59 PassOwnPtr<GIFImageDecoder> createDecoder()
     60 {
     61     return adoptPtr(new GIFImageDecoder(ImageSource::AlphaNotPremultiplied, ImageSource::GammaAndColorProfileApplied, ImageDecoder::noDecodedImageByteLimit));
     62 }
     63 
     64 unsigned hashSkBitmap(const SkBitmap& bitmap)
     65 {
     66     return StringHasher::hashMemory(bitmap.getPixels(), bitmap.getSize());
     67 }
     68 
     69 void createDecodingBaseline(SharedBuffer* data, Vector<unsigned>* baselineHashes)
     70 {
     71     OwnPtr<GIFImageDecoder> decoder = createDecoder();
     72     decoder->setData(data, true);
     73     size_t frameCount = decoder->frameCount();
     74     for (size_t i = 0; i < frameCount; ++i) {
     75         ImageFrame* frame = decoder->frameBufferAtIndex(i);
     76         baselineHashes->append(hashSkBitmap(frame->getSkBitmap()));
     77     }
     78 }
     79 
     80 void testRandomFrameDecode(const char* gifFile)
     81 {
     82     SCOPED_TRACE(gifFile);
     83 
     84     RefPtr<SharedBuffer> fullData = readFile(gifFile);
     85     ASSERT_TRUE(fullData.get());
     86     Vector<unsigned> baselineHashes;
     87     createDecodingBaseline(fullData.get(), &baselineHashes);
     88     size_t frameCount = baselineHashes.size();
     89 
     90     // Random decoding should get the same results as sequential decoding.
     91     OwnPtr<GIFImageDecoder> decoder = createDecoder();
     92     decoder->setData(fullData.get(), true);
     93     const size_t skippingStep = 5;
     94     for (size_t i = 0; i < skippingStep; ++i) {
     95         for (size_t j = i; j < frameCount; j += skippingStep) {
     96             SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
     97             ImageFrame* frame = decoder->frameBufferAtIndex(j);
     98             EXPECT_EQ(baselineHashes[j], hashSkBitmap(frame->getSkBitmap()));
     99         }
    100     }
    101 
    102     // Decoding in reverse order.
    103     decoder = createDecoder();
    104     decoder->setData(fullData.get(), true);
    105     for (size_t i = frameCount; i; --i) {
    106         SCOPED_TRACE(testing::Message() << "Reverse i:" << i);
    107         ImageFrame* frame = decoder->frameBufferAtIndex(i - 1);
    108         EXPECT_EQ(baselineHashes[i - 1], hashSkBitmap(frame->getSkBitmap()));
    109     }
    110 }
    111 
    112 void testRandomDecodeAfterClearFrameBufferCache(const char* gifFile)
    113 {
    114     SCOPED_TRACE(gifFile);
    115 
    116     RefPtr<SharedBuffer> data = readFile(gifFile);
    117     ASSERT_TRUE(data.get());
    118     Vector<unsigned> baselineHashes;
    119     createDecodingBaseline(data.get(), &baselineHashes);
    120     size_t frameCount = baselineHashes.size();
    121 
    122     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    123     decoder->setData(data.get(), true);
    124     for (size_t clearExceptFrame = 0; clearExceptFrame < frameCount; ++clearExceptFrame) {
    125         decoder->clearCacheExceptFrame(clearExceptFrame);
    126         const size_t skippingStep = 5;
    127         for (size_t i = 0; i < skippingStep; ++i) {
    128             for (size_t j = 0; j < frameCount; j += skippingStep) {
    129                 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
    130                 ImageFrame* frame = decoder->frameBufferAtIndex(j);
    131                 EXPECT_EQ(baselineHashes[j], hashSkBitmap(frame->getSkBitmap()));
    132             }
    133         }
    134     }
    135 }
    136 
    137 } // namespace
    138 
    139 TEST(GIFImageDecoderTest, decodeTwoFrames)
    140 {
    141     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    142 
    143     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    144     ASSERT_TRUE(data.get());
    145     decoder->setData(data.get(), true);
    146     EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
    147 
    148     ImageFrame* frame = decoder->frameBufferAtIndex(0);
    149     uint32_t generationID0 = frame->getSkBitmap().getGenerationID();
    150     EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
    151     EXPECT_EQ(16, frame->getSkBitmap().width());
    152     EXPECT_EQ(16, frame->getSkBitmap().height());
    153 
    154     frame = decoder->frameBufferAtIndex(1);
    155     uint32_t generationID1 = frame->getSkBitmap().getGenerationID();
    156     EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
    157     EXPECT_EQ(16, frame->getSkBitmap().width());
    158     EXPECT_EQ(16, frame->getSkBitmap().height());
    159     EXPECT_TRUE(generationID0 != generationID1);
    160 
    161     EXPECT_EQ(2u, decoder->frameCount());
    162     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    163 }
    164 
    165 TEST(GIFImageDecoderTest, parseAndDecode)
    166 {
    167     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    168 
    169     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    170     ASSERT_TRUE(data.get());
    171     decoder->setData(data.get(), true);
    172     EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
    173 
    174     // This call will parse the entire file.
    175     EXPECT_EQ(2u, decoder->frameCount());
    176 
    177     ImageFrame* frame = decoder->frameBufferAtIndex(0);
    178     EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
    179     EXPECT_EQ(16, frame->getSkBitmap().width());
    180     EXPECT_EQ(16, frame->getSkBitmap().height());
    181 
    182     frame = decoder->frameBufferAtIndex(1);
    183     EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
    184     EXPECT_EQ(16, frame->getSkBitmap().width());
    185     EXPECT_EQ(16, frame->getSkBitmap().height());
    186     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    187 }
    188 
    189 TEST(GIFImageDecoderTest, parseByteByByte)
    190 {
    191     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    192 
    193     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    194     ASSERT_TRUE(data.get());
    195 
    196     size_t frameCount = 0;
    197 
    198     // Pass data to decoder byte by byte.
    199     for (size_t length = 1; length <= data->size(); ++length) {
    200         RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), length);
    201         decoder->setData(tempData.get(), length == data->size());
    202 
    203         EXPECT_LE(frameCount, decoder->frameCount());
    204         frameCount = decoder->frameCount();
    205     }
    206 
    207     EXPECT_EQ(2u, decoder->frameCount());
    208 
    209     decoder->frameBufferAtIndex(0);
    210     decoder->frameBufferAtIndex(1);
    211     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    212 }
    213 
    214 TEST(GIFImageDecoderTest, parseAndDecodeByteByByte)
    215 {
    216     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    217 
    218     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated-gif-with-offsets.gif");
    219     ASSERT_TRUE(data.get());
    220 
    221     size_t frameCount = 0;
    222     size_t framesDecoded = 0;
    223 
    224     // Pass data to decoder byte by byte.
    225     for (size_t length = 1; length <= data->size(); ++length) {
    226         RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), length);
    227         decoder->setData(tempData.get(), length == data->size());
    228 
    229         EXPECT_LE(frameCount, decoder->frameCount());
    230         frameCount = decoder->frameCount();
    231 
    232         ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1);
    233         if (frame && frame->status() == ImageFrame::FrameComplete && framesDecoded < frameCount)
    234             ++framesDecoded;
    235     }
    236 
    237     EXPECT_EQ(5u, decoder->frameCount());
    238     EXPECT_EQ(5u, framesDecoded);
    239     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    240 }
    241 
    242 TEST(GIFImageDecoderTest, brokenSecondFrame)
    243 {
    244     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    245 
    246     RefPtr<SharedBuffer> data = readFile("/Source/web/tests/data/broken.gif");
    247     ASSERT_TRUE(data.get());
    248     decoder->setData(data.get(), true);
    249 
    250     // One frame is detected but cannot be decoded.
    251     EXPECT_EQ(1u, decoder->frameCount());
    252     ImageFrame* frame = decoder->frameBufferAtIndex(1);
    253     EXPECT_FALSE(frame);
    254 }
    255 
    256 TEST(GIFImageDecoderTest, progressiveDecode)
    257 {
    258     RefPtr<SharedBuffer> fullData = readFile("/Source/web/tests/data/radient.gif");
    259     ASSERT_TRUE(fullData.get());
    260     const size_t fullLength = fullData->size();
    261 
    262     OwnPtr<GIFImageDecoder> decoder;
    263     ImageFrame* frame;
    264 
    265     Vector<unsigned> truncatedHashes;
    266     Vector<unsigned> progressiveHashes;
    267 
    268     // Compute hashes when the file is truncated.
    269     const size_t increment = 1;
    270     for (size_t i = 1; i <= fullLength; i += increment) {
    271         decoder = createDecoder();
    272         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
    273         decoder->setData(data.get(), i == fullLength);
    274         frame = decoder->frameBufferAtIndex(0);
    275         if (!frame) {
    276             truncatedHashes.append(0);
    277             continue;
    278         }
    279         truncatedHashes.append(hashSkBitmap(frame->getSkBitmap()));
    280     }
    281 
    282     // Compute hashes when the file is progressively decoded.
    283     decoder = createDecoder();
    284     for (size_t i = 1; i <= fullLength; i += increment) {
    285         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
    286         decoder->setData(data.get(), i == fullLength);
    287         frame = decoder->frameBufferAtIndex(0);
    288         if (!frame) {
    289             progressiveHashes.append(0);
    290             continue;
    291         }
    292         progressiveHashes.append(hashSkBitmap(frame->getSkBitmap()));
    293     }
    294 
    295     bool match = true;
    296     for (size_t i = 0; i < truncatedHashes.size(); ++i) {
    297         if (truncatedHashes[i] != progressiveHashes[i]) {
    298             match = false;
    299             break;
    300         }
    301     }
    302     EXPECT_TRUE(match);
    303 }
    304 
    305 TEST(GIFImageDecoderTest, allDataReceivedTruncation)
    306 {
    307     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    308 
    309     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    310     ASSERT_TRUE(data.get());
    311 
    312     ASSERT_GE(data->size(), 10u);
    313     RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->size() - 10);
    314     decoder->setData(tempData.get(), true);
    315 
    316     EXPECT_EQ(2u, decoder->frameCount());
    317     EXPECT_FALSE(decoder->failed());
    318 
    319     decoder->frameBufferAtIndex(0);
    320     EXPECT_FALSE(decoder->failed());
    321     decoder->frameBufferAtIndex(1);
    322     EXPECT_TRUE(decoder->failed());
    323 }
    324 
    325 TEST(GIFImageDecoderTest, frameIsComplete)
    326 {
    327     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    328 
    329     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    330     ASSERT_TRUE(data.get());
    331     decoder->setData(data.get(), true);
    332 
    333     EXPECT_EQ(2u, decoder->frameCount());
    334     EXPECT_FALSE(decoder->failed());
    335     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
    336     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
    337 }
    338 
    339 TEST(GIFImageDecoderTest, frameIsCompleteLoading)
    340 {
    341     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    342 
    343     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    344     ASSERT_TRUE(data.get());
    345 
    346     ASSERT_GE(data->size(), 10u);
    347     RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->size() - 10);
    348     decoder->setData(tempData.get(), false);
    349 
    350     EXPECT_EQ(2u, decoder->frameCount());
    351     EXPECT_FALSE(decoder->failed());
    352     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
    353     EXPECT_FALSE(decoder->frameIsCompleteAtIndex(1));
    354 
    355     decoder->setData(data.get(), true);
    356     EXPECT_EQ(2u, decoder->frameCount());
    357     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
    358     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
    359 }
    360 
    361 TEST(GIFImageDecoderTest, badTerminator)
    362 {
    363     RefPtr<SharedBuffer> referenceData = readFile("/Source/web/tests/data/radient.gif");
    364     RefPtr<SharedBuffer> testData = readFile("/Source/web/tests/data/radient-bad-terminator.gif");
    365     ASSERT_TRUE(referenceData.get());
    366     ASSERT_TRUE(testData.get());
    367 
    368     OwnPtr<GIFImageDecoder> referenceDecoder(createDecoder());
    369     referenceDecoder->setData(referenceData.get(), true);
    370     EXPECT_EQ(1u, referenceDecoder->frameCount());
    371     ImageFrame* referenceFrame = referenceDecoder->frameBufferAtIndex(0);
    372     ASSERT(referenceFrame);
    373 
    374     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
    375     testDecoder->setData(testData.get(), true);
    376     EXPECT_EQ(1u, testDecoder->frameCount());
    377     ImageFrame* testFrame = testDecoder->frameBufferAtIndex(0);
    378     ASSERT(testFrame);
    379 
    380     EXPECT_EQ(hashSkBitmap(referenceFrame->getSkBitmap()), hashSkBitmap(testFrame->getSkBitmap()));
    381 }
    382 
    383 TEST(GIFImageDecoderTest, updateRequiredPreviousFrameAfterFirstDecode)
    384 {
    385     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    386 
    387     RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/animated-10color.gif");
    388     ASSERT_TRUE(fullData.get());
    389 
    390     // Give it data that is enough to parse but not decode in order to check the status
    391     // of requiredPreviousFrameIndex before decoding.
    392     size_t partialSize = 1;
    393     do {
    394         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
    395         decoder->setData(data.get(), false);
    396         ++partialSize;
    397     } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status() == ImageFrame::FrameEmpty);
    398 
    399     EXPECT_EQ(kNotFound, decoder->frameBufferAtIndex(0)->requiredPreviousFrameIndex());
    400     unsigned frameCount = decoder->frameCount();
    401     for (size_t i = 1; i < frameCount; ++i)
    402         EXPECT_EQ(i - 1, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex());
    403 
    404     decoder->setData(fullData.get(), true);
    405     for (size_t i = 0; i < frameCount; ++i)
    406         EXPECT_EQ(kNotFound, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex());
    407 }
    408 
    409 TEST(GIFImageDecoderTest, randomFrameDecode)
    410 {
    411     // Single frame image.
    412     testRandomFrameDecode("/Source/web/tests/data/radient.gif");
    413     // Multiple frame images.
    414     testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-gif-with-offsets.gif");
    415     testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-10color.gif");
    416 }
    417 
    418 TEST(GIFImageDecoderTest, randomDecodeAfterClearFrameBufferCache)
    419 {
    420     // Single frame image.
    421     testRandomDecodeAfterClearFrameBufferCache("/Source/web/tests/data/radient.gif");
    422     // Multiple frame images.
    423     testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/animated-gif-with-offsets.gif");
    424     testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/animated-10color.gif");
    425 }
    426 
    427 TEST(GIFImageDecoderTest, resumePartialDecodeAfterClearFrameBufferCache)
    428 {
    429     RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/animated-10color.gif");
    430     ASSERT_TRUE(fullData.get());
    431     Vector<unsigned> baselineHashes;
    432     createDecodingBaseline(fullData.get(), &baselineHashes);
    433     size_t frameCount = baselineHashes.size();
    434 
    435     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    436 
    437     // Let frame 0 be partially decoded.
    438     size_t partialSize = 1;
    439     do {
    440         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
    441         decoder->setData(data.get(), false);
    442         ++partialSize;
    443     } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status() == ImageFrame::FrameEmpty);
    444 
    445     // Skip to the last frame and clear.
    446     decoder->setData(fullData.get(), true);
    447     EXPECT_EQ(frameCount, decoder->frameCount());
    448     ImageFrame* lastFrame = decoder->frameBufferAtIndex(frameCount - 1);
    449     EXPECT_EQ(baselineHashes[frameCount - 1], hashSkBitmap(lastFrame->getSkBitmap()));
    450     decoder->clearCacheExceptFrame(kNotFound);
    451 
    452     // Resume decoding of the first frame.
    453     ImageFrame* firstFrame = decoder->frameBufferAtIndex(0);
    454     EXPECT_EQ(ImageFrame::FrameComplete, firstFrame->status());
    455     EXPECT_EQ(baselineHashes[0], hashSkBitmap(firstFrame->getSkBitmap()));
    456 }
    457 
    458 // The first LZW codes in the image are invalid values that try to create a loop
    459 // in the dictionary. Decoding should fail, but not infinitely loop or corrupt memory.
    460 TEST(GIFImageDecoderTest, badInitialCode)
    461 {
    462     RefPtr<SharedBuffer> testData = readFile("/Source/platform/image-decoders/testing/bad-initial-code.gif");
    463     ASSERT_TRUE(testData.get());
    464 
    465     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
    466     testDecoder->setData(testData.get(), true);
    467     EXPECT_EQ(1u, testDecoder->frameCount());
    468     ASSERT_TRUE(testDecoder->frameBufferAtIndex(0));
    469     EXPECT_TRUE(testDecoder->failed());
    470 }
    471 
    472 // The image has an invalid LZW code that exceeds dictionary size. Decoding should fail.
    473 TEST(GIFImageDecoderTest, badCode)
    474 {
    475     RefPtr<SharedBuffer> testData = readFile("/Source/platform/image-decoders/testing/bad-code.gif");
    476     ASSERT_TRUE(testData.get());
    477 
    478     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
    479     testDecoder->setData(testData.get(), true);
    480     EXPECT_EQ(1u, testDecoder->frameCount());
    481     ASSERT_TRUE(testDecoder->frameBufferAtIndex(0));
    482     EXPECT_TRUE(testDecoder->failed());
    483 }
    484 
    485 TEST(GIFImageDecoderTest, invalidDisposalMethod)
    486 {
    487     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    488 
    489     // The image has 2 frames, with disposal method 4 and 5, respectively.
    490     RefPtr<SharedBuffer> data = readFile("/Source/web/tests/data/invalid-disposal-method.gif");
    491     ASSERT_TRUE(data.get());
    492     decoder->setData(data.get(), true);
    493 
    494     EXPECT_EQ(2u, decoder->frameCount());
    495     // Disposal method 4 is converted to ImageFrame::DisposeOverwritePrevious.
    496     EXPECT_EQ(ImageFrame::DisposeOverwritePrevious, decoder->frameBufferAtIndex(0)->disposalMethod());
    497     // Disposal method 5 is ignored.
    498     EXPECT_EQ(ImageFrame::DisposeNotSpecified, decoder->frameBufferAtIndex(1)->disposalMethod());
    499 }
    500