Home | History | Annotate | Download | only in gif
      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 blink;
     47 
     48 namespace {
     49 
     50 PassRefPtr<SharedBuffer> readFile(const char* fileName)
     51 {
     52     String filePath = Platform::current()->unitTestSupport()->webKitRootDir();
     53     filePath.append(fileName);
     54 
     55     return Platform::current()->unitTestSupport()->readFromFile(filePath);
     56 }
     57 
     58 PassOwnPtr<GIFImageDecoder> createDecoder()
     59 {
     60     return adoptPtr(new GIFImageDecoder(ImageSource::AlphaNotPremultiplied, ImageSource::GammaAndColorProfileApplied, ImageDecoder::noDecodedImageByteLimit));
     61 }
     62 
     63 unsigned hashSkBitmap(const SkBitmap& bitmap)
     64 {
     65     return StringHasher::hashMemory(bitmap.getPixels(), bitmap.getSize());
     66 }
     67 
     68 void createDecodingBaseline(SharedBuffer* data, Vector<unsigned>* baselineHashes)
     69 {
     70     OwnPtr<GIFImageDecoder> decoder = createDecoder();
     71     decoder->setData(data, true);
     72     size_t frameCount = decoder->frameCount();
     73     for (size_t i = 0; i < frameCount; ++i) {
     74         ImageFrame* frame = decoder->frameBufferAtIndex(i);
     75         baselineHashes->append(hashSkBitmap(frame->getSkBitmap()));
     76     }
     77 }
     78 
     79 void testRandomFrameDecode(const char* gifFile)
     80 {
     81     SCOPED_TRACE(gifFile);
     82 
     83     RefPtr<SharedBuffer> fullData = readFile(gifFile);
     84     ASSERT_TRUE(fullData.get());
     85     Vector<unsigned> baselineHashes;
     86     createDecodingBaseline(fullData.get(), &baselineHashes);
     87     size_t frameCount = baselineHashes.size();
     88 
     89     // Random decoding should get the same results as sequential decoding.
     90     OwnPtr<GIFImageDecoder> decoder = createDecoder();
     91     decoder->setData(fullData.get(), true);
     92     const size_t skippingStep = 5;
     93     for (size_t i = 0; i < skippingStep; ++i) {
     94         for (size_t j = i; j < frameCount; j += skippingStep) {
     95             SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
     96             ImageFrame* frame = decoder->frameBufferAtIndex(j);
     97             EXPECT_EQ(baselineHashes[j], hashSkBitmap(frame->getSkBitmap()));
     98         }
     99     }
    100 
    101     // Decoding in reverse order.
    102     decoder = createDecoder();
    103     decoder->setData(fullData.get(), true);
    104     for (size_t i = frameCount; i; --i) {
    105         SCOPED_TRACE(testing::Message() << "Reverse i:" << i);
    106         ImageFrame* frame = decoder->frameBufferAtIndex(i - 1);
    107         EXPECT_EQ(baselineHashes[i - 1], hashSkBitmap(frame->getSkBitmap()));
    108     }
    109 }
    110 
    111 void testRandomDecodeAfterClearFrameBufferCache(const char* gifFile)
    112 {
    113     SCOPED_TRACE(gifFile);
    114 
    115     RefPtr<SharedBuffer> data = readFile(gifFile);
    116     ASSERT_TRUE(data.get());
    117     Vector<unsigned> baselineHashes;
    118     createDecodingBaseline(data.get(), &baselineHashes);
    119     size_t frameCount = baselineHashes.size();
    120 
    121     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    122     decoder->setData(data.get(), true);
    123     for (size_t clearExceptFrame = 0; clearExceptFrame < frameCount; ++clearExceptFrame) {
    124         decoder->clearCacheExceptFrame(clearExceptFrame);
    125         const size_t skippingStep = 5;
    126         for (size_t i = 0; i < skippingStep; ++i) {
    127             for (size_t j = 0; j < frameCount; j += skippingStep) {
    128                 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
    129                 ImageFrame* frame = decoder->frameBufferAtIndex(j);
    130                 EXPECT_EQ(baselineHashes[j], hashSkBitmap(frame->getSkBitmap()));
    131             }
    132         }
    133     }
    134 }
    135 
    136 } // namespace
    137 
    138 TEST(GIFImageDecoderTest, decodeTwoFrames)
    139 {
    140     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    141 
    142     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    143     ASSERT_TRUE(data.get());
    144     decoder->setData(data.get(), true);
    145     EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
    146 
    147     ImageFrame* frame = decoder->frameBufferAtIndex(0);
    148     uint32_t generationID0 = frame->getSkBitmap().getGenerationID();
    149     EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
    150     EXPECT_EQ(16, frame->getSkBitmap().width());
    151     EXPECT_EQ(16, frame->getSkBitmap().height());
    152 
    153     frame = decoder->frameBufferAtIndex(1);
    154     uint32_t generationID1 = frame->getSkBitmap().getGenerationID();
    155     EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
    156     EXPECT_EQ(16, frame->getSkBitmap().width());
    157     EXPECT_EQ(16, frame->getSkBitmap().height());
    158     EXPECT_TRUE(generationID0 != generationID1);
    159 
    160     EXPECT_EQ(2u, decoder->frameCount());
    161     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    162 }
    163 
    164 TEST(GIFImageDecoderTest, parseAndDecode)
    165 {
    166     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    167 
    168     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    169     ASSERT_TRUE(data.get());
    170     decoder->setData(data.get(), true);
    171     EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
    172 
    173     // This call will parse the entire file.
    174     EXPECT_EQ(2u, decoder->frameCount());
    175 
    176     ImageFrame* frame = decoder->frameBufferAtIndex(0);
    177     EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
    178     EXPECT_EQ(16, frame->getSkBitmap().width());
    179     EXPECT_EQ(16, frame->getSkBitmap().height());
    180 
    181     frame = decoder->frameBufferAtIndex(1);
    182     EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
    183     EXPECT_EQ(16, frame->getSkBitmap().width());
    184     EXPECT_EQ(16, frame->getSkBitmap().height());
    185     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    186 }
    187 
    188 TEST(GIFImageDecoderTest, parseByteByByte)
    189 {
    190     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    191 
    192     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    193     ASSERT_TRUE(data.get());
    194 
    195     size_t frameCount = 0;
    196 
    197     // Pass data to decoder byte by byte.
    198     for (size_t length = 1; length <= data->size(); ++length) {
    199         RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), length);
    200         decoder->setData(tempData.get(), length == data->size());
    201 
    202         EXPECT_LE(frameCount, decoder->frameCount());
    203         frameCount = decoder->frameCount();
    204     }
    205 
    206     EXPECT_EQ(2u, decoder->frameCount());
    207 
    208     decoder->frameBufferAtIndex(0);
    209     decoder->frameBufferAtIndex(1);
    210     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    211 }
    212 
    213 TEST(GIFImageDecoderTest, parseAndDecodeByteByByte)
    214 {
    215     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    216 
    217     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated-gif-with-offsets.gif");
    218     ASSERT_TRUE(data.get());
    219 
    220     size_t frameCount = 0;
    221     size_t framesDecoded = 0;
    222 
    223     // Pass data to decoder byte by byte.
    224     for (size_t length = 1; length <= data->size(); ++length) {
    225         RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), length);
    226         decoder->setData(tempData.get(), length == data->size());
    227 
    228         EXPECT_LE(frameCount, decoder->frameCount());
    229         frameCount = decoder->frameCount();
    230 
    231         ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1);
    232         if (frame && frame->status() == ImageFrame::FrameComplete && framesDecoded < frameCount)
    233             ++framesDecoded;
    234     }
    235 
    236     EXPECT_EQ(5u, decoder->frameCount());
    237     EXPECT_EQ(5u, framesDecoded);
    238     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    239 }
    240 
    241 TEST(GIFImageDecoderTest, brokenSecondFrame)
    242 {
    243     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    244 
    245     RefPtr<SharedBuffer> data = readFile("/Source/web/tests/data/broken.gif");
    246     ASSERT_TRUE(data.get());
    247     decoder->setData(data.get(), true);
    248 
    249     // One frame is detected but cannot be decoded.
    250     EXPECT_EQ(1u, decoder->frameCount());
    251     ImageFrame* frame = decoder->frameBufferAtIndex(1);
    252     EXPECT_FALSE(frame);
    253 }
    254 
    255 TEST(GIFImageDecoderTest, progressiveDecode)
    256 {
    257     RefPtr<SharedBuffer> fullData = readFile("/Source/web/tests/data/radient.gif");
    258     ASSERT_TRUE(fullData.get());
    259     const size_t fullLength = fullData->size();
    260 
    261     OwnPtr<GIFImageDecoder> decoder;
    262     ImageFrame* frame;
    263 
    264     Vector<unsigned> truncatedHashes;
    265     Vector<unsigned> progressiveHashes;
    266 
    267     // Compute hashes when the file is truncated.
    268     const size_t increment = 1;
    269     for (size_t i = 1; i <= fullLength; i += increment) {
    270         decoder = createDecoder();
    271         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
    272         decoder->setData(data.get(), i == fullLength);
    273         frame = decoder->frameBufferAtIndex(0);
    274         if (!frame) {
    275             truncatedHashes.append(0);
    276             continue;
    277         }
    278         truncatedHashes.append(hashSkBitmap(frame->getSkBitmap()));
    279     }
    280 
    281     // Compute hashes when the file is progressively decoded.
    282     decoder = createDecoder();
    283     EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
    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     EXPECT_EQ(cAnimationNone, decoder->repetitionCount());
    295 
    296     bool match = true;
    297     for (size_t i = 0; i < truncatedHashes.size(); ++i) {
    298         if (truncatedHashes[i] != progressiveHashes[i]) {
    299             match = false;
    300             break;
    301         }
    302     }
    303     EXPECT_TRUE(match);
    304 }
    305 
    306 TEST(GIFImageDecoderTest, allDataReceivedTruncation)
    307 {
    308     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    309 
    310     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    311     ASSERT_TRUE(data.get());
    312 
    313     ASSERT_GE(data->size(), 10u);
    314     RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->size() - 10);
    315     decoder->setData(tempData.get(), true);
    316 
    317     EXPECT_EQ(2u, decoder->frameCount());
    318     EXPECT_FALSE(decoder->failed());
    319 
    320     decoder->frameBufferAtIndex(0);
    321     EXPECT_FALSE(decoder->failed());
    322     decoder->frameBufferAtIndex(1);
    323     EXPECT_TRUE(decoder->failed());
    324 }
    325 
    326 TEST(GIFImageDecoderTest, frameIsComplete)
    327 {
    328     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    329 
    330     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    331     ASSERT_TRUE(data.get());
    332     decoder->setData(data.get(), true);
    333 
    334     EXPECT_EQ(2u, decoder->frameCount());
    335     EXPECT_FALSE(decoder->failed());
    336     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
    337     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
    338     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
    339 }
    340 
    341 TEST(GIFImageDecoderTest, frameIsCompleteLoading)
    342 {
    343     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    344 
    345     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
    346     ASSERT_TRUE(data.get());
    347 
    348     ASSERT_GE(data->size(), 10u);
    349     RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->size() - 10);
    350     decoder->setData(tempData.get(), false);
    351 
    352     EXPECT_EQ(2u, decoder->frameCount());
    353     EXPECT_FALSE(decoder->failed());
    354     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
    355     EXPECT_FALSE(decoder->frameIsCompleteAtIndex(1));
    356 
    357     decoder->setData(data.get(), true);
    358     EXPECT_EQ(2u, decoder->frameCount());
    359     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
    360     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
    361 }
    362 
    363 TEST(GIFImageDecoderTest, badTerminator)
    364 {
    365     RefPtr<SharedBuffer> referenceData = readFile("/Source/web/tests/data/radient.gif");
    366     RefPtr<SharedBuffer> testData = readFile("/Source/web/tests/data/radient-bad-terminator.gif");
    367     ASSERT_TRUE(referenceData.get());
    368     ASSERT_TRUE(testData.get());
    369 
    370     OwnPtr<GIFImageDecoder> referenceDecoder(createDecoder());
    371     referenceDecoder->setData(referenceData.get(), true);
    372     EXPECT_EQ(1u, referenceDecoder->frameCount());
    373     ImageFrame* referenceFrame = referenceDecoder->frameBufferAtIndex(0);
    374     ASSERT(referenceFrame);
    375 
    376     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
    377     testDecoder->setData(testData.get(), true);
    378     EXPECT_EQ(1u, testDecoder->frameCount());
    379     ImageFrame* testFrame = testDecoder->frameBufferAtIndex(0);
    380     ASSERT(testFrame);
    381 
    382     EXPECT_EQ(hashSkBitmap(referenceFrame->getSkBitmap()), hashSkBitmap(testFrame->getSkBitmap()));
    383 }
    384 
    385 TEST(GIFImageDecoderTest, updateRequiredPreviousFrameAfterFirstDecode)
    386 {
    387     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    388 
    389     RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/animated-10color.gif");
    390     ASSERT_TRUE(fullData.get());
    391 
    392     // Give it data that is enough to parse but not decode in order to check the status
    393     // of requiredPreviousFrameIndex before decoding.
    394     size_t partialSize = 1;
    395     do {
    396         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
    397         decoder->setData(data.get(), false);
    398         ++partialSize;
    399     } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status() == ImageFrame::FrameEmpty);
    400 
    401     EXPECT_EQ(kNotFound, decoder->frameBufferAtIndex(0)->requiredPreviousFrameIndex());
    402     unsigned frameCount = decoder->frameCount();
    403     for (size_t i = 1; i < frameCount; ++i)
    404         EXPECT_EQ(i - 1, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex());
    405 
    406     decoder->setData(fullData.get(), true);
    407     for (size_t i = 0; i < frameCount; ++i)
    408         EXPECT_EQ(kNotFound, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex());
    409 }
    410 
    411 TEST(GIFImageDecoderTest, randomFrameDecode)
    412 {
    413     // Single frame image.
    414     testRandomFrameDecode("/Source/web/tests/data/radient.gif");
    415     // Multiple frame images.
    416     testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-gif-with-offsets.gif");
    417     testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-10color.gif");
    418 }
    419 
    420 TEST(GIFImageDecoderTest, randomDecodeAfterClearFrameBufferCache)
    421 {
    422     // Single frame image.
    423     testRandomDecodeAfterClearFrameBufferCache("/Source/web/tests/data/radient.gif");
    424     // Multiple frame images.
    425     testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/animated-gif-with-offsets.gif");
    426     testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/animated-10color.gif");
    427 }
    428 
    429 TEST(GIFImageDecoderTest, resumePartialDecodeAfterClearFrameBufferCache)
    430 {
    431     RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/animated-10color.gif");
    432     ASSERT_TRUE(fullData.get());
    433     Vector<unsigned> baselineHashes;
    434     createDecodingBaseline(fullData.get(), &baselineHashes);
    435     size_t frameCount = baselineHashes.size();
    436 
    437     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    438 
    439     // Let frame 0 be partially decoded.
    440     size_t partialSize = 1;
    441     do {
    442         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
    443         decoder->setData(data.get(), false);
    444         ++partialSize;
    445     } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status() == ImageFrame::FrameEmpty);
    446 
    447     // Skip to the last frame and clear.
    448     decoder->setData(fullData.get(), true);
    449     EXPECT_EQ(frameCount, decoder->frameCount());
    450     ImageFrame* lastFrame = decoder->frameBufferAtIndex(frameCount - 1);
    451     EXPECT_EQ(baselineHashes[frameCount - 1], hashSkBitmap(lastFrame->getSkBitmap()));
    452     decoder->clearCacheExceptFrame(kNotFound);
    453 
    454     // Resume decoding of the first frame.
    455     ImageFrame* firstFrame = decoder->frameBufferAtIndex(0);
    456     EXPECT_EQ(ImageFrame::FrameComplete, firstFrame->status());
    457     EXPECT_EQ(baselineHashes[0], hashSkBitmap(firstFrame->getSkBitmap()));
    458 }
    459 
    460 // The first LZW codes in the image are invalid values that try to create a loop
    461 // in the dictionary. Decoding should fail, but not infinitely loop or corrupt memory.
    462 TEST(GIFImageDecoderTest, badInitialCode)
    463 {
    464     RefPtr<SharedBuffer> testData = readFile("/Source/platform/image-decoders/testing/bad-initial-code.gif");
    465     ASSERT_TRUE(testData.get());
    466 
    467     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
    468     testDecoder->setData(testData.get(), true);
    469     EXPECT_EQ(1u, testDecoder->frameCount());
    470     ASSERT_TRUE(testDecoder->frameBufferAtIndex(0));
    471     EXPECT_TRUE(testDecoder->failed());
    472 }
    473 
    474 // The image has an invalid LZW code that exceeds dictionary size. Decoding should fail.
    475 TEST(GIFImageDecoderTest, badCode)
    476 {
    477     RefPtr<SharedBuffer> testData = readFile("/Source/platform/image-decoders/testing/bad-code.gif");
    478     ASSERT_TRUE(testData.get());
    479 
    480     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
    481     testDecoder->setData(testData.get(), true);
    482     EXPECT_EQ(1u, testDecoder->frameCount());
    483     ASSERT_TRUE(testDecoder->frameBufferAtIndex(0));
    484     EXPECT_TRUE(testDecoder->failed());
    485 }
    486 
    487 TEST(GIFImageDecoderTest, invalidDisposalMethod)
    488 {
    489     OwnPtr<GIFImageDecoder> decoder = createDecoder();
    490 
    491     // The image has 2 frames, with disposal method 4 and 5, respectively.
    492     RefPtr<SharedBuffer> data = readFile("/Source/web/tests/data/invalid-disposal-method.gif");
    493     ASSERT_TRUE(data.get());
    494     decoder->setData(data.get(), true);
    495 
    496     EXPECT_EQ(2u, decoder->frameCount());
    497     // Disposal method 4 is converted to ImageFrame::DisposeOverwritePrevious.
    498     EXPECT_EQ(ImageFrame::DisposeOverwritePrevious, decoder->frameBufferAtIndex(0)->disposalMethod());
    499     // Disposal method 5 is ignored.
    500     EXPECT_EQ(ImageFrame::DisposeNotSpecified, decoder->frameBufferAtIndex(1)->disposalMethod());
    501 }
    502