| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/image-decoders/ImageDecoderTestHelpers.h" | 5 #include "platform/image-decoders/ImageDecoderTestHelpers.h" |
| 6 | 6 |
| 7 #include "platform/SharedBuffer.h" | 7 #include "platform/SharedBuffer.h" |
| 8 #include "platform/image-decoders/ImageDecoder.h" | |
| 9 #include "platform/image-decoders/ImageFrame.h" | 8 #include "platform/image-decoders/ImageFrame.h" |
| 10 #include "platform/testing/UnitTestHelpers.h" | 9 #include "platform/testing/UnitTestHelpers.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
| 12 #include "wtf/StringHasher.h" | 11 #include "wtf/StringHasher.h" |
| 13 #include "wtf/text/StringBuilder.h" | 12 #include "wtf/text/StringBuilder.h" |
| 14 #include <memory> | 13 #include <memory> |
| 15 | 14 |
| 16 namespace blink { | 15 namespace blink { |
| 17 | 16 |
| 18 PassRefPtr<SharedBuffer> readFile(const char* fileName) { | 17 PassRefPtr<SharedBuffer> readFile(const char* fileName) { |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 progressiveHashes.append(0); | 280 progressiveHashes.append(0); |
| 282 continue; | 281 continue; |
| 283 } | 282 } |
| 284 progressiveHashes.append(hashBitmap(frame->bitmap())); | 283 progressiveHashes.append(hashBitmap(frame->bitmap())); |
| 285 } | 284 } |
| 286 | 285 |
| 287 for (size_t i = 0; i < truncatedHashes.size(); ++i) | 286 for (size_t i = 0; i < truncatedHashes.size(); ++i) |
| 288 ASSERT_EQ(truncatedHashes[i], progressiveHashes[i]); | 287 ASSERT_EQ(truncatedHashes[i], progressiveHashes[i]); |
| 289 } | 288 } |
| 290 | 289 |
| 290 void testUpdateRequiredPreviousFrameAfterFirstDecode( |
| 291 DecoderCreator createDecoder, |
| 292 SharedBuffer* fullData) { |
| 293 std::unique_ptr<ImageDecoder> decoder = createDecoder(); |
| 294 |
| 295 // Give it data that is enough to parse but not decode in order to check the |
| 296 // status of requiredPreviousFrameIndex before decoding. |
| 297 size_t partialSize = 1; |
| 298 do { |
| 299 RefPtr<SharedBuffer> data = |
| 300 SharedBuffer::create(fullData->data(), partialSize); |
| 301 decoder->setData(data.get(), false); |
| 302 ++partialSize; |
| 303 } while (!decoder->frameCount() || |
| 304 decoder->frameBufferAtIndex(0)->getStatus() == |
| 305 ImageFrame::FrameEmpty); |
| 306 |
| 307 EXPECT_EQ(kNotFound, |
| 308 decoder->frameBufferAtIndex(0)->requiredPreviousFrameIndex()); |
| 309 unsigned frameCount = decoder->frameCount(); |
| 310 for (size_t i = 1; i < frameCount; ++i) { |
| 311 EXPECT_EQ(i - 1, |
| 312 decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex()); |
| 313 } |
| 314 |
| 315 decoder->setData(fullData, true); |
| 316 for (size_t i = 0; i < frameCount; ++i) { |
| 317 EXPECT_EQ(kNotFound, |
| 318 decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex()); |
| 319 } |
| 320 } |
| 321 |
| 322 void testResumePartialDecodeAfterClearFrameBufferCache( |
| 323 DecoderCreator createDecoder, |
| 324 SharedBuffer* fullData) { |
| 325 Vector<unsigned> baselineHashes; |
| 326 createDecodingBaseline(createDecoder, fullData, &baselineHashes); |
| 327 size_t frameCount = baselineHashes.size(); |
| 328 |
| 329 std::unique_ptr<ImageDecoder> decoder = createDecoder(); |
| 330 |
| 331 // Let frame 0 be partially decoded. |
| 332 size_t partialSize = 1; |
| 333 do { |
| 334 RefPtr<SharedBuffer> data = |
| 335 SharedBuffer::create(fullData->data(), partialSize); |
| 336 decoder->setData(data.get(), false); |
| 337 ++partialSize; |
| 338 } while (!decoder->frameCount() || |
| 339 decoder->frameBufferAtIndex(0)->getStatus() == |
| 340 ImageFrame::FrameEmpty); |
| 341 |
| 342 // Skip to the last frame and clear. |
| 343 decoder->setData(fullData, true); |
| 344 EXPECT_EQ(frameCount, decoder->frameCount()); |
| 345 ImageFrame* lastFrame = decoder->frameBufferAtIndex(frameCount - 1); |
| 346 EXPECT_EQ(baselineHashes[frameCount - 1], hashBitmap(lastFrame->bitmap())); |
| 347 decoder->clearCacheExceptFrame(kNotFound); |
| 348 |
| 349 // Resume decoding of the first frame. |
| 350 ImageFrame* firstFrame = decoder->frameBufferAtIndex(0); |
| 351 EXPECT_EQ(ImageFrame::FrameComplete, firstFrame->getStatus()); |
| 352 EXPECT_EQ(baselineHashes[0], hashBitmap(firstFrame->bitmap())); |
| 353 } |
| 354 |
| 291 void testByteByByteDecode(DecoderCreator createDecoder, | 355 void testByteByByteDecode(DecoderCreator createDecoder, |
| 292 const char* file, | 356 const char* file, |
| 293 size_t expectedFrameCount, | 357 size_t expectedFrameCount, |
| 294 int expectedRepetitionCount) { | 358 int expectedRepetitionCount) { |
| 295 RefPtr<SharedBuffer> data = readFile(file); | 359 RefPtr<SharedBuffer> data = readFile(file); |
| 296 ASSERT_TRUE(data.get()); | 360 ASSERT_TRUE(data.get()); |
| 297 testByteByByteDecode(createDecoder, data.get(), expectedFrameCount, | 361 testByteByByteDecode(createDecoder, data.get(), expectedFrameCount, |
| 298 expectedRepetitionCount); | 362 expectedRepetitionCount); |
| 299 } | 363 } |
| 300 void testByteByByteDecode(DecoderCreator createDecoder, | 364 void testByteByByteDecode(DecoderCreator createDecoder, |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 | 473 |
| 410 void testProgressiveDecoding(DecoderCreator createDecoder, | 474 void testProgressiveDecoding(DecoderCreator createDecoder, |
| 411 const char* dir, | 475 const char* dir, |
| 412 const char* file, | 476 const char* file, |
| 413 size_t increment) { | 477 size_t increment) { |
| 414 RefPtr<SharedBuffer> data = readFile(dir, file); | 478 RefPtr<SharedBuffer> data = readFile(dir, file); |
| 415 ASSERT_TRUE(data.get()); | 479 ASSERT_TRUE(data.get()); |
| 416 testProgressiveDecoding(createDecoder, data.get(), increment); | 480 testProgressiveDecoding(createDecoder, data.get(), increment); |
| 417 } | 481 } |
| 418 | 482 |
| 483 void testUpdateRequiredPreviousFrameAfterFirstDecode( |
| 484 DecoderCreator createDecoder, |
| 485 const char* dir, |
| 486 const char* file) { |
| 487 RefPtr<SharedBuffer> data = readFile(dir, file); |
| 488 ASSERT_TRUE(data.get()); |
| 489 testUpdateRequiredPreviousFrameAfterFirstDecode(createDecoder, data.get()); |
| 490 } |
| 491 |
| 492 void testUpdateRequiredPreviousFrameAfterFirstDecode( |
| 493 DecoderCreator createDecoder, |
| 494 const char* file) { |
| 495 RefPtr<SharedBuffer> data = readFile(file); |
| 496 ASSERT_TRUE(data.get()); |
| 497 testUpdateRequiredPreviousFrameAfterFirstDecode(createDecoder, data.get()); |
| 498 } |
| 499 |
| 500 void testResumePartialDecodeAfterClearFrameBufferCache( |
| 501 DecoderCreator createDecoder, |
| 502 const char* dir, |
| 503 const char* file) { |
| 504 RefPtr<SharedBuffer> data = readFile(dir, file); |
| 505 ASSERT_TRUE(data.get()); |
| 506 testResumePartialDecodeAfterClearFrameBufferCache(createDecoder, data.get()); |
| 507 } |
| 508 |
| 509 void testResumePartialDecodeAfterClearFrameBufferCache( |
| 510 DecoderCreator createDecoder, |
| 511 const char* file) { |
| 512 RefPtr<SharedBuffer> data = readFile(file); |
| 513 ASSERT_TRUE(data.get()); |
| 514 testResumePartialDecodeAfterClearFrameBufferCache(createDecoder, data.get()); |
| 515 } |
| 516 |
| 517 static uint32_t premultiplyColor(uint32_t c) { |
| 518 return SkPremultiplyARGBInline(SkGetPackedA32(c), SkGetPackedR32(c), |
| 519 SkGetPackedG32(c), SkGetPackedB32(c)); |
| 520 } |
| 521 |
| 522 static void verifyFramesMatch(const char* file, |
| 523 const ImageFrame* const a, |
| 524 const ImageFrame* const b) { |
| 525 const SkBitmap& bitmapA = a->bitmap(); |
| 526 const SkBitmap& bitmapB = b->bitmap(); |
| 527 ASSERT_EQ(bitmapA.width(), bitmapB.width()); |
| 528 ASSERT_EQ(bitmapA.height(), bitmapB.height()); |
| 529 |
| 530 int maxDifference = 0; |
| 531 for (int y = 0; y < bitmapA.height(); ++y) { |
| 532 for (int x = 0; x < bitmapA.width(); ++x) { |
| 533 uint32_t colorA = *bitmapA.getAddr32(x, y); |
| 534 if (!a->premultiplyAlpha()) |
| 535 colorA = premultiplyColor(colorA); |
| 536 uint32_t colorB = *bitmapB.getAddr32(x, y); |
| 537 if (!b->premultiplyAlpha()) |
| 538 colorB = premultiplyColor(colorB); |
| 539 uint8_t* pixelA = reinterpret_cast<uint8_t*>(&colorA); |
| 540 uint8_t* pixelB = reinterpret_cast<uint8_t*>(&colorB); |
| 541 for (int channel = 0; channel < 4; ++channel) { |
| 542 const int difference = abs(pixelA[channel] - pixelB[channel]); |
| 543 if (difference > maxDifference) |
| 544 maxDifference = difference; |
| 545 } |
| 546 } |
| 547 } |
| 548 |
| 549 // Pre-multiplication could round the RGBA channel values. So, we declare |
| 550 // that the frames match if the RGBA channel values differ by at most 2. |
| 551 EXPECT_GE(2, maxDifference) << file; |
| 552 } |
| 553 |
| 554 // Verifies that result of alpha blending is similar for AlphaPremultiplied and |
| 555 // AlphaNotPremultiplied cases. |
| 556 void testAlphaBlending(DecoderCreatorWithAlpha createDecoder, |
| 557 const char* file) { |
| 558 RefPtr<SharedBuffer> data = readFile(file); |
| 559 ASSERT_TRUE(data.get()); |
| 560 |
| 561 std::unique_ptr<ImageDecoder> decoderA = |
| 562 createDecoder(ImageDecoder::AlphaPremultiplied); |
| 563 decoderA->setData(data.get(), true); |
| 564 |
| 565 std::unique_ptr<ImageDecoder> decoderB = |
| 566 createDecoder(ImageDecoder::AlphaNotPremultiplied); |
| 567 decoderB->setData(data.get(), true); |
| 568 |
| 569 size_t frameCount = decoderA->frameCount(); |
| 570 ASSERT_EQ(frameCount, decoderB->frameCount()); |
| 571 |
| 572 for (size_t i = 0; i < frameCount; ++i) { |
| 573 verifyFramesMatch(file, decoderA->frameBufferAtIndex(i), |
| 574 decoderB->frameBufferAtIndex(i)); |
| 575 } |
| 576 } |
| 577 |
| 419 } // namespace blink | 578 } // namespace blink |
| OLD | NEW |