c17188e85dbd260e2721ab5ff56b3de9eff6e740
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / image-decoders / gif / GIFImageDecoderTest.cpp
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     EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
285     for (size_t i = 1; i <= fullLength; i += increment) {
286         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
287         decoder->setData(data.get(), i == fullLength);
288         frame = decoder->frameBufferAtIndex(0);
289         if (!frame) {
290             progressiveHashes.append(0);
291             continue;
292         }
293         progressiveHashes.append(hashSkBitmap(frame->getSkBitmap()));
294     }
295     EXPECT_EQ(cAnimationNone, decoder->repetitionCount());
296
297     bool match = true;
298     for (size_t i = 0; i < truncatedHashes.size(); ++i) {
299         if (truncatedHashes[i] != progressiveHashes[i]) {
300             match = false;
301             break;
302         }
303     }
304     EXPECT_TRUE(match);
305 }
306
307 TEST(GIFImageDecoderTest, allDataReceivedTruncation)
308 {
309     OwnPtr<GIFImageDecoder> decoder = createDecoder();
310
311     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
312     ASSERT_TRUE(data.get());
313
314     ASSERT_GE(data->size(), 10u);
315     RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->size() - 10);
316     decoder->setData(tempData.get(), true);
317
318     EXPECT_EQ(2u, decoder->frameCount());
319     EXPECT_FALSE(decoder->failed());
320
321     decoder->frameBufferAtIndex(0);
322     EXPECT_FALSE(decoder->failed());
323     decoder->frameBufferAtIndex(1);
324     EXPECT_TRUE(decoder->failed());
325 }
326
327 TEST(GIFImageDecoderTest, frameIsComplete)
328 {
329     OwnPtr<GIFImageDecoder> decoder = createDecoder();
330
331     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
332     ASSERT_TRUE(data.get());
333     decoder->setData(data.get(), true);
334
335     EXPECT_EQ(2u, decoder->frameCount());
336     EXPECT_FALSE(decoder->failed());
337     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
338     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
339     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
340 }
341
342 TEST(GIFImageDecoderTest, frameIsCompleteLoading)
343 {
344     OwnPtr<GIFImageDecoder> decoder = createDecoder();
345
346     RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/animated.gif");
347     ASSERT_TRUE(data.get());
348
349     ASSERT_GE(data->size(), 10u);
350     RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->size() - 10);
351     decoder->setData(tempData.get(), false);
352
353     EXPECT_EQ(2u, decoder->frameCount());
354     EXPECT_FALSE(decoder->failed());
355     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
356     EXPECT_FALSE(decoder->frameIsCompleteAtIndex(1));
357
358     decoder->setData(data.get(), true);
359     EXPECT_EQ(2u, decoder->frameCount());
360     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
361     EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
362 }
363
364 TEST(GIFImageDecoderTest, badTerminator)
365 {
366     RefPtr<SharedBuffer> referenceData = readFile("/Source/web/tests/data/radient.gif");
367     RefPtr<SharedBuffer> testData = readFile("/Source/web/tests/data/radient-bad-terminator.gif");
368     ASSERT_TRUE(referenceData.get());
369     ASSERT_TRUE(testData.get());
370
371     OwnPtr<GIFImageDecoder> referenceDecoder(createDecoder());
372     referenceDecoder->setData(referenceData.get(), true);
373     EXPECT_EQ(1u, referenceDecoder->frameCount());
374     ImageFrame* referenceFrame = referenceDecoder->frameBufferAtIndex(0);
375     ASSERT(referenceFrame);
376
377     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
378     testDecoder->setData(testData.get(), true);
379     EXPECT_EQ(1u, testDecoder->frameCount());
380     ImageFrame* testFrame = testDecoder->frameBufferAtIndex(0);
381     ASSERT(testFrame);
382
383     EXPECT_EQ(hashSkBitmap(referenceFrame->getSkBitmap()), hashSkBitmap(testFrame->getSkBitmap()));
384 }
385
386 TEST(GIFImageDecoderTest, updateRequiredPreviousFrameAfterFirstDecode)
387 {
388     OwnPtr<GIFImageDecoder> decoder = createDecoder();
389
390     RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/animated-10color.gif");
391     ASSERT_TRUE(fullData.get());
392
393     // Give it data that is enough to parse but not decode in order to check the status
394     // of requiredPreviousFrameIndex before decoding.
395     size_t partialSize = 1;
396     do {
397         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
398         decoder->setData(data.get(), false);
399         ++partialSize;
400     } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status() == ImageFrame::FrameEmpty);
401
402     EXPECT_EQ(kNotFound, decoder->frameBufferAtIndex(0)->requiredPreviousFrameIndex());
403     unsigned frameCount = decoder->frameCount();
404     for (size_t i = 1; i < frameCount; ++i)
405         EXPECT_EQ(i - 1, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex());
406
407     decoder->setData(fullData.get(), true);
408     for (size_t i = 0; i < frameCount; ++i)
409         EXPECT_EQ(kNotFound, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex());
410 }
411
412 TEST(GIFImageDecoderTest, randomFrameDecode)
413 {
414     // Single frame image.
415     testRandomFrameDecode("/Source/web/tests/data/radient.gif");
416     // Multiple frame images.
417     testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-gif-with-offsets.gif");
418     testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-10color.gif");
419 }
420
421 TEST(GIFImageDecoderTest, randomDecodeAfterClearFrameBufferCache)
422 {
423     // Single frame image.
424     testRandomDecodeAfterClearFrameBufferCache("/Source/web/tests/data/radient.gif");
425     // Multiple frame images.
426     testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/animated-gif-with-offsets.gif");
427     testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/animated-10color.gif");
428 }
429
430 TEST(GIFImageDecoderTest, resumePartialDecodeAfterClearFrameBufferCache)
431 {
432     RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/animated-10color.gif");
433     ASSERT_TRUE(fullData.get());
434     Vector<unsigned> baselineHashes;
435     createDecodingBaseline(fullData.get(), &baselineHashes);
436     size_t frameCount = baselineHashes.size();
437
438     OwnPtr<GIFImageDecoder> decoder = createDecoder();
439
440     // Let frame 0 be partially decoded.
441     size_t partialSize = 1;
442     do {
443         RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
444         decoder->setData(data.get(), false);
445         ++partialSize;
446     } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status() == ImageFrame::FrameEmpty);
447
448     // Skip to the last frame and clear.
449     decoder->setData(fullData.get(), true);
450     EXPECT_EQ(frameCount, decoder->frameCount());
451     ImageFrame* lastFrame = decoder->frameBufferAtIndex(frameCount - 1);
452     EXPECT_EQ(baselineHashes[frameCount - 1], hashSkBitmap(lastFrame->getSkBitmap()));
453     decoder->clearCacheExceptFrame(kNotFound);
454
455     // Resume decoding of the first frame.
456     ImageFrame* firstFrame = decoder->frameBufferAtIndex(0);
457     EXPECT_EQ(ImageFrame::FrameComplete, firstFrame->status());
458     EXPECT_EQ(baselineHashes[0], hashSkBitmap(firstFrame->getSkBitmap()));
459 }
460
461 // The first LZW codes in the image are invalid values that try to create a loop
462 // in the dictionary. Decoding should fail, but not infinitely loop or corrupt memory.
463 TEST(GIFImageDecoderTest, badInitialCode)
464 {
465     RefPtr<SharedBuffer> testData = readFile("/Source/platform/image-decoders/testing/bad-initial-code.gif");
466     ASSERT_TRUE(testData.get());
467
468     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
469     testDecoder->setData(testData.get(), true);
470     EXPECT_EQ(1u, testDecoder->frameCount());
471     ASSERT_TRUE(testDecoder->frameBufferAtIndex(0));
472     EXPECT_TRUE(testDecoder->failed());
473 }
474
475 // The image has an invalid LZW code that exceeds dictionary size. Decoding should fail.
476 TEST(GIFImageDecoderTest, badCode)
477 {
478     RefPtr<SharedBuffer> testData = readFile("/Source/platform/image-decoders/testing/bad-code.gif");
479     ASSERT_TRUE(testData.get());
480
481     OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
482     testDecoder->setData(testData.get(), true);
483     EXPECT_EQ(1u, testDecoder->frameCount());
484     ASSERT_TRUE(testDecoder->frameBufferAtIndex(0));
485     EXPECT_TRUE(testDecoder->failed());
486 }
487
488 TEST(GIFImageDecoderTest, invalidDisposalMethod)
489 {
490     OwnPtr<GIFImageDecoder> decoder = createDecoder();
491
492     // The image has 2 frames, with disposal method 4 and 5, respectively.
493     RefPtr<SharedBuffer> data = readFile("/Source/web/tests/data/invalid-disposal-method.gif");
494     ASSERT_TRUE(data.get());
495     decoder->setData(data.get(), true);
496
497     EXPECT_EQ(2u, decoder->frameCount());
498     // Disposal method 4 is converted to ImageFrame::DisposeOverwritePrevious.
499     EXPECT_EQ(ImageFrame::DisposeOverwritePrevious, decoder->frameBufferAtIndex(0)->disposalMethod());
500     // Disposal method 5 is ignored.
501     EXPECT_EQ(ImageFrame::DisposeNotSpecified, decoder->frameBufferAtIndex(1)->disposalMethod());
502 }