| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "Resources.h" | 8 #include "Resources.h" |
| 9 #include "SkAndroidCodec.h" | 9 #include "SkAndroidCodec.h" |
| 10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
| 11 #include "SkCodec.h" | 11 #include "SkCodec.h" |
| 12 #include "SkData.h" | 12 #include "SkData.h" |
| 13 #include "SkMD5.h" | 13 #include "SkMD5.h" |
| 14 #include "SkRandom.h" | 14 #include "SkRandom.h" |
| 15 #include "SkStream.h" | |
| 16 #include "SkPngChunkReader.h" | |
| 17 #include "Test.h" | 15 #include "Test.h" |
| 18 | 16 |
| 19 #include "png.h" | |
| 20 | |
| 21 static SkStreamAsset* resource(const char path[]) { | 17 static SkStreamAsset* resource(const char path[]) { |
| 22 SkString fullPath = GetResourcePath(path); | 18 SkString fullPath = GetResourcePath(path); |
| 23 return SkStream::NewFromFile(fullPath.c_str()); | 19 return SkStream::NewFromFile(fullPath.c_str()); |
| 24 } | 20 } |
| 25 | 21 |
| 26 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) { | 22 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) { |
| 27 SkAutoLockPixels autoLockPixels(bm); | 23 SkAutoLockPixels autoLockPixels(bm); |
| 28 SkASSERT(bm.getPixels()); | 24 SkASSERT(bm.getPixels()); |
| 29 SkMD5 md5; | 25 SkMD5 md5; |
| 30 size_t rowLen = bm.info().bytesPerPixel() * bm.width(); | 26 size_t rowLen = bm.info().bytesPerPixel() * bm.width(); |
| (...skipping 651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 678 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 683 result = decoder->startScanlineDecode( | 679 result = decoder->startScanlineDecode( |
| 684 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); | 680 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); |
| 685 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 681 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 686 } | 682 } |
| 687 | 683 |
| 688 DEF_TEST(Codec_Params, r) { | 684 DEF_TEST(Codec_Params, r) { |
| 689 test_invalid_parameters(r, "index8.png"); | 685 test_invalid_parameters(r, "index8.png"); |
| 690 test_invalid_parameters(r, "mandrill.wbmp"); | 686 test_invalid_parameters(r, "mandrill.wbmp"); |
| 691 } | 687 } |
| 692 | |
| 693 static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t
len) { | |
| 694 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); | |
| 695 if (!sk_stream->write(data, len)) { | |
| 696 png_error(png_ptr, "sk_write_fn Error!"); | |
| 697 } | |
| 698 } | |
| 699 | |
| 700 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED | |
| 701 DEF_TEST(Codec_pngChunkReader, r) { | |
| 702 // Create a dummy bitmap. Use unpremul RGBA for libpng. | |
| 703 SkBitmap bm; | |
| 704 const int w = 1; | |
| 705 const int h = 1; | |
| 706 const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, | |
| 707 kUnpremul_SkAlphaType); | |
| 708 bm.setInfo(bmInfo); | |
| 709 bm.allocPixels(); | |
| 710 bm.eraseColor(SK_ColorBLUE); | |
| 711 SkMD5::Digest goodDigest; | |
| 712 md5(bm, &goodDigest); | |
| 713 | |
| 714 // Write to a png file. | |
| 715 png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nu
llptr, nullptr); | |
| 716 REPORTER_ASSERT(r, png); | |
| 717 if (!png) { | |
| 718 return; | |
| 719 } | |
| 720 | |
| 721 png_infop info = png_create_info_struct(png); | |
| 722 REPORTER_ASSERT(r, info); | |
| 723 if (!info) { | |
| 724 png_destroy_write_struct(&png, nullptr); | |
| 725 return; | |
| 726 } | |
| 727 | |
| 728 if (setjmp(png_jmpbuf(png))) { | |
| 729 ERRORF(r, "failed writing png"); | |
| 730 png_destroy_write_struct(&png, &info); | |
| 731 return; | |
| 732 } | |
| 733 | |
| 734 SkDynamicMemoryWStream wStream; | |
| 735 png_set_write_fn(png, (void*) (&wStream), codex_test_write_fn, nullptr); | |
| 736 | |
| 737 png_set_IHDR(png, info, (png_uint_32)w, (png_uint_32)h, 8, | |
| 738 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, | |
| 739 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | |
| 740 | |
| 741 // Create some chunks that match the Android framework's use. | |
| 742 static png_unknown_chunk gUnknowns[] = { | |
| 743 { "npOl", (png_byte*)"outline", sizeof("outline"), PNG_HAVE_PLTE }, | |
| 744 { "npLb", (png_byte*)"layoutBounds", sizeof("layoutBounds"), PNG_HAVE_PL
TE }, | |
| 745 { "npTc", (png_byte*)"ninePatchData", sizeof("ninePatchData"), PNG_HAVE_
PLTE }, | |
| 746 }; | |
| 747 | |
| 748 png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"npOl\0
npLb\0npTc\0", 3); | |
| 749 png_set_unknown_chunks(png, info, gUnknowns, SK_ARRAY_COUNT(gUnknowns)); | |
| 750 #if PNG_LIBPNG_VER < 10600 | |
| 751 /* Deal with unknown chunk location bug in 1.5.x and earlier */ | |
| 752 png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_PLTE); | |
| 753 png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_PLTE); | |
| 754 #endif | |
| 755 | |
| 756 png_write_info(png, info); | |
| 757 | |
| 758 for (int j = 0; j < h; j++) { | |
| 759 png_bytep row = (png_bytep)(bm.getAddr(0, j)); | |
| 760 png_write_rows(png, &row, 1); | |
| 761 } | |
| 762 png_write_end(png, info); | |
| 763 png_destroy_write_struct(&png, &info); | |
| 764 | |
| 765 class ChunkReader : public SkPngChunkReader { | |
| 766 public: | |
| 767 ChunkReader(skiatest::Reporter* r) | |
| 768 : fReporter(r) | |
| 769 { | |
| 770 this->reset(); | |
| 771 } | |
| 772 | |
| 773 bool readChunk(const char tag[], const void* data, size_t length) overri
de { | |
| 774 for (size_t i = 0; i < SK_ARRAY_COUNT(gUnknowns); ++i) { | |
| 775 if (!strcmp(tag, (const char*) gUnknowns[i].name)) { | |
| 776 // Tag matches. This should have been the first time we see
it. | |
| 777 REPORTER_ASSERT(fReporter, !fSeen[i]); | |
| 778 fSeen[i] = true; | |
| 779 | |
| 780 // Data and length should match | |
| 781 REPORTER_ASSERT(fReporter, length == gUnknowns[i].size); | |
| 782 REPORTER_ASSERT(fReporter, !strcmp((const char*) data, | |
| 783 (const char*) gUnknowns[i
].data)); | |
| 784 return true; | |
| 785 } | |
| 786 } | |
| 787 ERRORF(fReporter, "Saw an unexpected unknown chunk."); | |
| 788 return true; | |
| 789 } | |
| 790 | |
| 791 bool allHaveBeenSeen() { | |
| 792 bool ret = true; | |
| 793 for (auto seen : fSeen) { | |
| 794 ret &= seen; | |
| 795 } | |
| 796 return ret; | |
| 797 } | |
| 798 | |
| 799 void reset() { | |
| 800 sk_bzero(fSeen, sizeof(fSeen)); | |
| 801 } | |
| 802 | |
| 803 private: | |
| 804 skiatest::Reporter* fReporter; // Unowned | |
| 805 bool fSeen[3]; | |
| 806 }; | |
| 807 | |
| 808 ChunkReader chunkReader(r); | |
| 809 | |
| 810 // Now read the file with SkCodec. | |
| 811 SkAutoTUnref<SkData> data(wStream.copyToData()); | |
| 812 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data, &chunkReader)); | |
| 813 REPORTER_ASSERT(r, codec); | |
| 814 if (!codec) { | |
| 815 return; | |
| 816 } | |
| 817 | |
| 818 // Now compare to the original. | |
| 819 SkBitmap decodedBm; | |
| 820 decodedBm.setInfo(codec->getInfo()); | |
| 821 decodedBm.allocPixels(); | |
| 822 SkCodec::Result result = codec->getPixels(codec->getInfo(), decodedBm.getPix
els(), | |
| 823 decodedBm.rowBytes()); | |
| 824 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | |
| 825 | |
| 826 if (decodedBm.colorType() != bm.colorType()) { | |
| 827 SkBitmap tmp; | |
| 828 bool success = decodedBm.copyTo(&tmp, bm.colorType()); | |
| 829 REPORTER_ASSERT(r, success); | |
| 830 if (!success) { | |
| 831 return; | |
| 832 } | |
| 833 | |
| 834 tmp.swap(decodedBm); | |
| 835 } | |
| 836 | |
| 837 compare_to_good_digest(r, goodDigest, decodedBm); | |
| 838 REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen()); | |
| 839 | |
| 840 // Decoding again will read the chunks again. | |
| 841 chunkReader.reset(); | |
| 842 REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen()); | |
| 843 result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm
.rowBytes()); | |
| 844 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | |
| 845 REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen()); | |
| 846 } | |
| 847 #endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED | |
| OLD | NEW |