OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 14 matching lines...) Expand all Loading... |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "config.h" | 31 #include "config.h" |
32 | 32 |
33 #include "core/platform/image-decoders/gif/GIFImageDecoder.h" | 33 #include "core/platform/image-decoders/gif/GIFImageDecoder.h" |
34 | 34 |
35 #include <gtest/gtest.h> | |
36 #include "core/platform/FileSystem.h" | 35 #include "core/platform/FileSystem.h" |
37 #include "core/platform/SharedBuffer.h" | 36 #include "core/platform/SharedBuffer.h" |
| 37 #include "wtf/OwnPtr.h" |
| 38 #include "wtf/PassOwnPtr.h" |
| 39 #include "wtf/StringHasher.h" |
| 40 #include "wtf/Vector.h" |
| 41 #include <gtest/gtest.h> |
38 #include <public/Platform.h> | 42 #include <public/Platform.h> |
39 #include <public/WebData.h> | 43 #include <public/WebData.h> |
40 #include <public/WebSize.h> | 44 #include <public/WebSize.h> |
41 #include <public/WebUnitTestSupport.h> | 45 #include <public/WebUnitTestSupport.h> |
42 #include <wtf/OwnPtr.h> | |
43 #include <wtf/PassOwnPtr.h> | |
44 #include <wtf/StringHasher.h> | |
45 #include <wtf/Vector.h> | |
46 | 46 |
47 using namespace WebCore; | 47 using namespace WebCore; |
48 using namespace WebKit; | 48 using namespace WebKit; |
49 | 49 |
50 namespace { | 50 namespace { |
51 | 51 |
52 #if !OS(ANDROID) | 52 #if !OS(ANDROID) |
53 | 53 |
54 static PassRefPtr<SharedBuffer> readFile(const char* fileName) | 54 static PassRefPtr<SharedBuffer> readFile(const char* fileName) |
55 { | 55 { |
(...skipping 15 matching lines...) Expand all Loading... |
71 static PassOwnPtr<GIFImageDecoder> createDecoder() | 71 static PassOwnPtr<GIFImageDecoder> createDecoder() |
72 { | 72 { |
73 return adoptPtr(new GIFImageDecoder(ImageSource::AlphaNotPremultiplied, Imag
eSource::GammaAndColorProfileApplied)); | 73 return adoptPtr(new GIFImageDecoder(ImageSource::AlphaNotPremultiplied, Imag
eSource::GammaAndColorProfileApplied)); |
74 } | 74 } |
75 | 75 |
76 static unsigned hashSkBitmap(const SkBitmap& bitmap) | 76 static unsigned hashSkBitmap(const SkBitmap& bitmap) |
77 { | 77 { |
78 return StringHasher::hashMemory(bitmap.getPixels(), bitmap.getSize()); | 78 return StringHasher::hashMemory(bitmap.getPixels(), bitmap.getSize()); |
79 } | 79 } |
80 | 80 |
| 81 static void createDecodingBaseline(SharedBuffer* data, Vector<unsigned>* baselin
eHashes) |
| 82 { |
| 83 OwnPtr<GIFImageDecoder> decoder(createDecoder()); |
| 84 decoder->setData(data, true); |
| 85 size_t frameCount = decoder->frameCount(); |
| 86 for (size_t i = 0; i < frameCount; ++i) { |
| 87 ImageFrame* frame = decoder->frameBufferAtIndex(i); |
| 88 baselineHashes->append(hashSkBitmap(frame->getSkBitmap())); |
| 89 } |
| 90 } |
| 91 |
81 TEST(GIFImageDecoderTest, decodeTwoFrames) | 92 TEST(GIFImageDecoderTest, decodeTwoFrames) |
82 { | 93 { |
83 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | 94 OwnPtr<GIFImageDecoder> decoder(createDecoder()); |
84 | 95 |
85 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | 96 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); |
86 ASSERT_TRUE(data.get()); | 97 ASSERT_TRUE(data.get()); |
87 decoder->setData(data.get(), true); | 98 decoder->setData(data.get(), true); |
88 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount()); | 99 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount()); |
89 | 100 |
90 ImageFrame* frame = decoder->frameBufferAtIndex(0); | 101 ImageFrame* frame = decoder->frameBufferAtIndex(0); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 TEST(GIFImageDecoderTest, parseByteByByte) | 139 TEST(GIFImageDecoderTest, parseByteByByte) |
129 { | 140 { |
130 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | 141 OwnPtr<GIFImageDecoder> decoder(createDecoder()); |
131 | 142 |
132 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | 143 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); |
133 ASSERT_TRUE(data.get()); | 144 ASSERT_TRUE(data.get()); |
134 | 145 |
135 size_t frameCount = 0; | 146 size_t frameCount = 0; |
136 | 147 |
137 // Pass data to decoder byte by byte. | 148 // Pass data to decoder byte by byte. |
138 for (unsigned length = 1; length <= data->size(); ++length) { | 149 for (size_t length = 1; length <= data->size(); ++length) { |
139 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt
h); | 150 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt
h); |
140 decoder->setData(tempData.get(), length == data->size()); | 151 decoder->setData(tempData.get(), length == data->size()); |
141 | 152 |
142 EXPECT_LE(frameCount, decoder->frameCount()); | 153 EXPECT_LE(frameCount, decoder->frameCount()); |
143 frameCount = decoder->frameCount(); | 154 frameCount = decoder->frameCount(); |
144 } | 155 } |
145 | 156 |
146 EXPECT_EQ(2u, decoder->frameCount()); | 157 EXPECT_EQ(2u, decoder->frameCount()); |
147 | 158 |
148 decoder->frameBufferAtIndex(0); | 159 decoder->frameBufferAtIndex(0); |
149 decoder->frameBufferAtIndex(1); | 160 decoder->frameBufferAtIndex(1); |
150 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | 161 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); |
151 } | 162 } |
152 | 163 |
153 TEST(GIFImageDecoderTest, parseAndDecodeByteByByte) | 164 TEST(GIFImageDecoderTest, parseAndDecodeByteByByte) |
154 { | 165 { |
155 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | 166 OwnPtr<GIFImageDecoder> decoder(createDecoder()); |
156 | 167 |
157 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated-gif-with-offsets.gif"); | 168 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated-gif-with-offsets.gif"); |
158 ASSERT_TRUE(data.get()); | 169 ASSERT_TRUE(data.get()); |
159 | 170 |
160 size_t frameCount = 0; | 171 size_t frameCount = 0; |
161 size_t framesDecoded = 0; | 172 size_t framesDecoded = 0; |
162 | 173 |
163 // Pass data to decoder byte by byte. | 174 // Pass data to decoder byte by byte. |
164 for (unsigned length = 1; length <= data->size(); ++length) { | 175 for (size_t length = 1; length <= data->size(); ++length) { |
165 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt
h); | 176 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt
h); |
166 decoder->setData(tempData.get(), length == data->size()); | 177 decoder->setData(tempData.get(), length == data->size()); |
167 | 178 |
168 EXPECT_LE(frameCount, decoder->frameCount()); | 179 EXPECT_LE(frameCount, decoder->frameCount()); |
169 frameCount = decoder->frameCount(); | 180 frameCount = decoder->frameCount(); |
170 | 181 |
171 ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1); | 182 ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1); |
172 if (frame && frame->status() == ImageFrame::FrameComplete && framesDecod
ed < frameCount) | 183 if (frame && frame->status() == ImageFrame::FrameComplete && framesDecod
ed < frameCount) |
173 ++framesDecoded; | 184 ++framesDecoded; |
174 } | 185 } |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 EXPECT_FALSE(decoder->failed()); | 301 EXPECT_FALSE(decoder->failed()); |
291 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | 302 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); |
292 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(1)); | 303 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(1)); |
293 | 304 |
294 decoder->setData(data.get(), true); | 305 decoder->setData(data.get(), true); |
295 EXPECT_EQ(2u, decoder->frameCount()); | 306 EXPECT_EQ(2u, decoder->frameCount()); |
296 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | 307 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); |
297 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1)); | 308 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1)); |
298 } | 309 } |
299 | 310 |
| 311 TEST(GIFImageDecoderTest, updateRequiredPreviousFrameAfterFirstDecode) |
| 312 { |
| 313 OwnPtr<GIFImageDecoder> decoder(createDecoder()); |
| 314 |
| 315 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources
/animated-10color.gif"); |
| 316 ASSERT_TRUE(fullData.get()); |
| 317 |
| 318 // Give it data that is enough to parse but not decode in order to check the
status |
| 319 // of requiredPreviousFrameIndex before decoding. |
| 320 size_t partialSize = 1; |
| 321 do { |
| 322 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), parti
alSize); |
| 323 decoder->setData(data.get(), false); |
| 324 ++partialSize; |
| 325 } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status()
== ImageFrame::FrameEmpty); |
| 326 |
| 327 EXPECT_EQ(notFound, decoder->frameBufferAtIndex(0)->requiredPreviousFrameInd
ex()); |
| 328 unsigned frameCount = decoder->frameCount(); |
| 329 for (size_t i = 1; i < frameCount; ++i) |
| 330 EXPECT_EQ(i - 1, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIn
dex()); |
| 331 |
| 332 decoder->setData(fullData.get(), true); |
| 333 for (size_t i = 0; i < frameCount; ++i) |
| 334 EXPECT_EQ(notFound, decoder->frameBufferAtIndex(i)->requiredPreviousFram
eIndex()); |
| 335 } |
| 336 |
| 337 void testRandomFrameDecode(const char* gifFile) |
| 338 { |
| 339 SCOPED_TRACE(gifFile); |
| 340 |
| 341 RefPtr<SharedBuffer> fullData = readFile(gifFile); |
| 342 ASSERT_TRUE(fullData.get()); |
| 343 Vector<unsigned> baselineHashes; |
| 344 createDecodingBaseline(fullData.get(), &baselineHashes); |
| 345 size_t frameCount = baselineHashes.size(); |
| 346 |
| 347 // Random decoding should get the same results as sequential decoding. |
| 348 OwnPtr<GIFImageDecoder> decoder(createDecoder()); |
| 349 decoder->setData(fullData.get(), true); |
| 350 const size_t skippingStep = 5; |
| 351 for (size_t i = 0; i < skippingStep; ++i) { |
| 352 for (size_t j = i; j < frameCount; j += skippingStep) { |
| 353 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j); |
| 354 ImageFrame* frame = decoder->frameBufferAtIndex(j); |
| 355 EXPECT_EQ(baselineHashes[j], hashSkBitmap(frame->getSkBitmap())); |
| 356 } |
| 357 } |
| 358 |
| 359 // Decoding in reverse order. |
| 360 decoder = createDecoder(); |
| 361 decoder->setData(fullData.get(), true); |
| 362 for (size_t i = frameCount; i; --i) { |
| 363 SCOPED_TRACE(testing::Message() << "Reverse i:" << i); |
| 364 ImageFrame* frame = decoder->frameBufferAtIndex(i - 1); |
| 365 EXPECT_EQ(baselineHashes[i - 1], hashSkBitmap(frame->getSkBitmap())); |
| 366 } |
| 367 } |
| 368 |
| 369 TEST(GIFImageDecoderTest, randomFrameDecode) |
| 370 { |
| 371 // Single frame image. |
| 372 testRandomFrameDecode("/Source/WebKit/chromium/tests/data/radient.gif"); |
| 373 // Multiple frame image. |
| 374 testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-gif-with-
offsets.gif"); |
| 375 testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-10color.g
if"); |
| 376 } |
| 377 |
| 378 void testRandomDecodeAfterClearFrameBufferCache(const char* gifFile) |
| 379 { |
| 380 SCOPED_TRACE(gifFile); |
| 381 |
| 382 RefPtr<SharedBuffer> data = readFile(gifFile); |
| 383 ASSERT_TRUE(data.get()); |
| 384 Vector<unsigned> baselineHashes; |
| 385 createDecodingBaseline(data.get(), &baselineHashes); |
| 386 size_t frameCount = baselineHashes.size(); |
| 387 |
| 388 OwnPtr<GIFImageDecoder> decoder(createDecoder()); |
| 389 for (size_t clearExceptFrame = 0; clearExceptFrame < frameCount; ++clearExce
ptFrame) { |
| 390 decoder->clearCacheExceptFrame(clearExceptFrame); |
| 391 const size_t skippingStep = 5; |
| 392 for (size_t i = 0; i < skippingStep; ++i) { |
| 393 for (size_t j = 0; j < frameCount; j += skippingStep) { |
| 394 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" <<
j); |
| 395 ImageFrame* frame = decoder->frameBufferAtIndex(j); |
| 396 EXPECT_EQ(baselineHashes[j], hashSkBitmap(frame->getSkBitmap()))
; |
| 397 } |
| 398 } |
| 399 } |
| 400 } |
| 401 |
| 402 TEST(GIFImageDecoderTest, randomDecodeAfterClearFrameBufferCache) |
| 403 { |
| 404 // Single frame image. |
| 405 testRandomFrameDecode("/Source/WebKit/chromium/tests/data/radient.gif"); |
| 406 // Multiple frame image. |
| 407 testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-gif-with-
offsets.gif"); |
| 408 testRandomFrameDecode("/LayoutTests/fast/images/resources/animated-10color.g
if"); |
| 409 } |
| 410 |
| 411 TEST(GIFImageDecoderTest, resumePartialDecodeAfterClearFrameBufferCache) |
| 412 { |
| 413 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources
/animated-10color.gif"); |
| 414 ASSERT_TRUE(fullData.get()); |
| 415 Vector<unsigned> baselineHashes; |
| 416 createDecodingBaseline(fullData.get(), &baselineHashes); |
| 417 size_t frameCount = baselineHashes.size(); |
| 418 |
| 419 OwnPtr<GIFImageDecoder> decoder(createDecoder()); |
| 420 |
| 421 // Let frame 0 be partially decoded. |
| 422 size_t partialSize = 1; |
| 423 do { |
| 424 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), parti
alSize); |
| 425 decoder->setData(data.get(), false); |
| 426 ++partialSize; |
| 427 } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status()
== ImageFrame::FrameEmpty); |
| 428 |
| 429 // Skip to the last frame and clear. |
| 430 decoder->setData(fullData.get(), true); |
| 431 EXPECT_EQ(frameCount, decoder->frameCount()); |
| 432 ImageFrame* lastFrame = decoder->frameBufferAtIndex(frameCount - 1); |
| 433 EXPECT_EQ(baselineHashes[frameCount - 1], hashSkBitmap(lastFrame->getSkBitma
p())); |
| 434 decoder->clearCacheExceptFrame(notFound); |
| 435 |
| 436 // Resume decoding of the first frame. |
| 437 ImageFrame* firstFrame = decoder->frameBufferAtIndex(0); |
| 438 EXPECT_EQ(ImageFrame::FrameComplete, firstFrame->status()); |
| 439 EXPECT_EQ(baselineHashes[0], hashSkBitmap(firstFrame->getSkBitmap())); |
| 440 } |
| 441 |
300 #endif | 442 #endif |
301 | 443 |
302 } // namespace | 444 } // namespace |
OLD | NEW |