| 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" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 md5(bm, &digest); | 49 md5(bm, &digest); |
| 50 REPORTER_ASSERT(r, digest == goodDigest); | 50 REPORTER_ASSERT(r, digest == goodDigest); |
| 51 } | 51 } |
| 52 | 52 |
| 53 /** | 53 /** |
| 54 * Test decoding an SkCodec to a particular SkImageInfo. | 54 * Test decoding an SkCodec to a particular SkImageInfo. |
| 55 * | 55 * |
| 56 * Calling getPixels(info) should return expectedResult, and if goodDigest is n
on nullptr, | 56 * Calling getPixels(info) should return expectedResult, and if goodDigest is n
on nullptr, |
| 57 * the resulting decode should match. | 57 * the resulting decode should match. |
| 58 */ | 58 */ |
| 59 static void test_info(skiatest::Reporter* r, SkCodec* codec, const SkImageInfo&
info, | 59 template<typename Codec> |
| 60 static void test_info(skiatest::Reporter* r, Codec* codec, const SkImageInfo& in
fo, |
| 60 SkCodec::Result expectedResult, const SkMD5::Digest* goodD
igest) { | 61 SkCodec::Result expectedResult, const SkMD5::Digest* goodD
igest) { |
| 61 SkBitmap bm; | 62 SkBitmap bm; |
| 62 bm.allocPixels(info); | 63 bm.allocPixels(info); |
| 63 SkAutoLockPixels autoLockPixels(bm); | 64 SkAutoLockPixels autoLockPixels(bm); |
| 64 | 65 |
| 65 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); | 66 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); |
| 66 REPORTER_ASSERT(r, result == expectedResult); | 67 REPORTER_ASSERT(r, result == expectedResult); |
| 67 | 68 |
| 68 if (goodDigest) { | 69 if (goodDigest) { |
| 69 compare_to_good_digest(r, *goodDigest, bm); | 70 compare_to_good_digest(r, *goodDigest, bm); |
| 70 } | 71 } |
| 71 } | 72 } |
| 72 | 73 |
| 73 static void test_android_info(skiatest::Reporter* r, SkAndroidCodec* codec, cons
t SkImageInfo& info, | |
| 74 SkCodec::Result expectedResult, const SkMD5::Diges
t* goodDigest) { | |
| 75 SkBitmap bm; | |
| 76 bm.allocPixels(info); | |
| 77 SkAutoLockPixels autoLockPixels(bm); | |
| 78 | |
| 79 SkCodec::Result result = codec->getAndroidPixels(info, bm.getPixels(), bm.ro
wBytes()); | |
| 80 REPORTER_ASSERT(r, result == expectedResult); | |
| 81 | |
| 82 if (goodDigest) { | |
| 83 compare_to_good_digest(r, *goodDigest, bm); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 SkIRect generate_random_subset(SkRandom* rand, int w, int h) { | 74 SkIRect generate_random_subset(SkRandom* rand, int w, int h) { |
| 88 SkIRect rect; | 75 SkIRect rect; |
| 89 do { | 76 do { |
| 90 rect.fLeft = rand->nextRangeU(0, w); | 77 rect.fLeft = rand->nextRangeU(0, w); |
| 91 rect.fTop = rand->nextRangeU(0, h); | 78 rect.fTop = rand->nextRangeU(0, h); |
| 92 rect.fRight = rand->nextRangeU(0, w); | 79 rect.fRight = rand->nextRangeU(0, w); |
| 93 rect.fBottom = rand->nextRangeU(0, h); | 80 rect.fBottom = rand->nextRangeU(0, h); |
| 94 rect.sort(); | 81 rect.sort(); |
| 95 } while (rect.isEmpty()); | 82 } while (rect.isEmpty()); |
| 96 return rect; | 83 return rect; |
| 97 } | 84 } |
| 98 | 85 |
| 99 static void test_codec(skiatest::Reporter* r, SkCodec* codec, SkBitmap& bm, cons
t SkImageInfo& info, | 86 template<typename Codec> |
| 87 static void test_codec(skiatest::Reporter* r, Codec* codec, SkBitmap& bm, const
SkImageInfo& info, |
| 100 const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* dige
st, | 88 const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* dige
st, |
| 101 const SkMD5::Digest* goodDigest) { | 89 const SkMD5::Digest* goodDigest) { |
| 102 | 90 |
| 103 REPORTER_ASSERT(r, info.dimensions() == size); | 91 REPORTER_ASSERT(r, info.dimensions() == size); |
| 104 bm.allocPixels(info); | 92 bm.allocPixels(info); |
| 105 SkAutoLockPixels autoLockPixels(bm); | 93 SkAutoLockPixels autoLockPixels(bm); |
| 106 | 94 |
| 107 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); | 95 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); |
| 108 REPORTER_ASSERT(r, result == expectedResult); | 96 REPORTER_ASSERT(r, result == expectedResult); |
| 109 | 97 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 otherAt = kUnpremul_SkAlphaType; | 130 otherAt = kUnpremul_SkAlphaType; |
| 143 } else { | 131 } else { |
| 144 otherAt = kPremul_SkAlphaType; | 132 otherAt = kPremul_SkAlphaType; |
| 145 } | 133 } |
| 146 // The other non-opaque alpha type should always succeed, but not ma
tch. | 134 // The other non-opaque alpha type should always succeed, but not ma
tch. |
| 147 test_info(r, codec, info.makeAlphaType(otherAt), expectedResult, nul
lptr); | 135 test_info(r, codec, info.makeAlphaType(otherAt), expectedResult, nul
lptr); |
| 148 } | 136 } |
| 149 } | 137 } |
| 150 } | 138 } |
| 151 | 139 |
| 152 static void test_android_codec(skiatest::Reporter* r, SkAndroidCodec* codec, SkB
itmap& bm, | |
| 153 const SkImageInfo& info, const SkISize& size, SkCodec::Result expectedRe
sult, | |
| 154 SkMD5::Digest* digest, const SkMD5::Digest* goodDigest) { | |
| 155 | |
| 156 REPORTER_ASSERT(r, info.dimensions() == size); | |
| 157 bm.allocPixels(info); | |
| 158 SkAutoLockPixels autoLockPixels(bm); | |
| 159 | |
| 160 SkCodec::Result result = codec->getAndroidPixels(info, bm.getPixels(), bm.ro
wBytes()); | |
| 161 REPORTER_ASSERT(r, result == expectedResult); | |
| 162 | |
| 163 md5(bm, digest); | |
| 164 if (goodDigest) { | |
| 165 REPORTER_ASSERT(r, *digest == *goodDigest); | |
| 166 } | |
| 167 | |
| 168 { | |
| 169 // Test decoding to 565 | |
| 170 SkImageInfo info565 = info.makeColorType(kRGB_565_SkColorType); | |
| 171 SkCodec::Result expected565 = info.alphaType() == kOpaque_SkAlphaType ? | |
| 172 expectedResult : SkCodec::kInvalidConversion; | |
| 173 test_android_info(r, codec, info565, expected565, nullptr); | |
| 174 } | |
| 175 | |
| 176 // Verify that re-decoding gives the same result. It is interesting to chec
k this after | |
| 177 // a decode to 565, since choosing to decode to 565 may result in some of th
e decode | |
| 178 // options being modified. These options should return to their defaults on
another | |
| 179 // decode to kN32, so the new digest should match the old digest. | |
| 180 test_android_info(r, codec, info, expectedResult, digest); | |
| 181 | |
| 182 { | |
| 183 // Check alpha type conversions | |
| 184 if (info.alphaType() == kOpaque_SkAlphaType) { | |
| 185 test_android_info(r, codec, info.makeAlphaType(kUnpremul_SkAlphaType
), | |
| 186 expectedResult, digest); | |
| 187 test_android_info(r, codec, info.makeAlphaType(kPremul_SkAlphaType), | |
| 188 expectedResult, digest); | |
| 189 } else { | |
| 190 // Decoding to opaque should fail | |
| 191 test_android_info(r, codec, info.makeAlphaType(kOpaque_SkAlphaType), | |
| 192 SkCodec::kInvalidConversion, nullptr); | |
| 193 SkAlphaType otherAt = info.alphaType(); | |
| 194 if (kPremul_SkAlphaType == otherAt) { | |
| 195 otherAt = kUnpremul_SkAlphaType; | |
| 196 } else { | |
| 197 otherAt = kPremul_SkAlphaType; | |
| 198 } | |
| 199 // The other non-opaque alpha type should always succeed, but not ma
tch. | |
| 200 test_android_info(r, codec, info.makeAlphaType(otherAt), expectedRes
ult, nullptr); | |
| 201 } | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 // FIXME: SkScaledCodec is currently only supported for types used by BRD | 140 // FIXME: SkScaledCodec is currently only supported for types used by BRD |
| 206 // https://bug.skia.org/4428 | 141 // https://bug.skia.org/4428 |
| 207 static bool supports_scaled_codec(const char path[]) { | 142 static bool supports_scaled_codec(const char path[]) { |
| 208 static const char* const exts[] = { | 143 static const char* const exts[] = { |
| 209 "jpg", "jpeg", "png", "webp" | 144 "jpg", "jpeg", "png", "webp" |
| 210 "JPG", "JPEG", "PNG", "WEBP" | 145 "JPG", "JPEG", "PNG", "WEBP" |
| 211 }; | 146 }; |
| 212 | 147 |
| 213 for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { | 148 for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { |
| 214 if (SkStrEndsWith(path, exts[i])) { | 149 if (SkStrEndsWith(path, exts[i])) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 243 if (!codec) { | 178 if (!codec) { |
| 244 ERRORF(r, "Unable to decode '%s'", path); | 179 ERRORF(r, "Unable to decode '%s'", path); |
| 245 return; | 180 return; |
| 246 } | 181 } |
| 247 | 182 |
| 248 // Test full image decodes with SkCodec | 183 // Test full image decodes with SkCodec |
| 249 SkMD5::Digest codecDigest; | 184 SkMD5::Digest codecDigest; |
| 250 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); | 185 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
| 251 SkBitmap bm; | 186 SkBitmap bm; |
| 252 SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput :
SkCodec::kSuccess; | 187 SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput :
SkCodec::kSuccess; |
| 253 test_codec(r, codec, bm, info, size, expectedResult, &codecDigest, nullptr); | 188 test_codec(r, codec.get(), bm, info, size, expectedResult, &codecDigest, nul
lptr); |
| 254 | 189 |
| 255 // Scanline decoding follows. | 190 // Scanline decoding follows. |
| 256 // Need to call startScanlineDecode() first. | 191 // Need to call startScanlineDecode() first. |
| 257 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 192 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
| 258 == 0); | 193 == 0); |
| 259 REPORTER_ASSERT(r, codec->skipScanlines(1) | 194 REPORTER_ASSERT(r, codec->skipScanlines(1) |
| 260 == 0); | 195 == 0); |
| 261 | 196 |
| 262 const SkCodec::Result startResult = codec->startScanlineDecode(info); | 197 const SkCodec::Result startResult = codec->startScanlineDecode(info); |
| 263 if (supportsScanlineDecoding) { | 198 if (supportsScanlineDecoding) { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 | 289 |
| 355 // SkScaledCodec tests | 290 // SkScaledCodec tests |
| 356 if ((supportsScanlineDecoding || supportsSubsetDecoding) && supports_scaled_
codec(path)) { | 291 if ((supportsScanlineDecoding || supportsSubsetDecoding) && supports_scaled_
codec(path)) { |
| 357 | 292 |
| 358 SkAutoTDelete<SkStream> stream(resource(path)); | 293 SkAutoTDelete<SkStream> stream(resource(path)); |
| 359 if (!stream) { | 294 if (!stream) { |
| 360 SkDebugf("Missing resource '%s'\n", path); | 295 SkDebugf("Missing resource '%s'\n", path); |
| 361 return; | 296 return; |
| 362 } | 297 } |
| 363 | 298 |
| 364 SkAutoTDelete<SkAndroidCodec> codec(nullptr); | 299 SkAutoTDelete<SkAndroidCodec> androidCodec(nullptr); |
| 365 if (isIncomplete) { | 300 if (isIncomplete) { |
| 366 size_t size = stream->getLength(); | 301 size_t size = stream->getLength(); |
| 367 SkAutoTUnref<SkData> data((SkData::NewFromStream(stream, 2 * size /
3))); | 302 SkAutoTUnref<SkData> data((SkData::NewFromStream(stream, 2 * size /
3))); |
| 368 codec.reset(SkAndroidCodec::NewFromData(data)); | 303 androidCodec.reset(SkAndroidCodec::NewFromData(data)); |
| 369 } else { | 304 } else { |
| 370 codec.reset(SkAndroidCodec::NewFromStream(stream.detach())); | 305 androidCodec.reset(SkAndroidCodec::NewFromStream(stream.detach())); |
| 371 } | 306 } |
| 372 if (!codec) { | 307 if (!androidCodec) { |
| 373 ERRORF(r, "Unable to decode '%s'", path); | 308 ERRORF(r, "Unable to decode '%s'", path); |
| 374 return; | 309 return; |
| 375 } | 310 } |
| 376 | 311 |
| 377 SkBitmap bm; | 312 SkBitmap bm; |
| 378 SkMD5::Digest scaledCodecDigest; | 313 SkMD5::Digest scaledCodecDigest; |
| 379 test_android_codec(r, codec, bm, info, size, expectedResult, | 314 test_codec(r, androidCodec.get(), bm, info, size, expectedResult, &scale
dCodecDigest, |
| 380 &scaledCodecDigest, &codecDigest); | 315 &codecDigest); |
| 381 } | 316 } |
| 382 | 317 |
| 383 // Test SkCodecImageGenerator | 318 // Test SkCodecImageGenerator |
| 384 if (!isIncomplete) { | 319 if (!isIncomplete) { |
| 385 SkAutoTDelete<SkStream> stream(resource(path)); | 320 SkAutoTDelete<SkStream> stream(resource(path)); |
| 386 SkAutoTUnref<SkData> fullData(SkData::NewFromStream(stream, stream->getL
ength())); | 321 SkAutoTUnref<SkData> fullData(SkData::NewFromStream(stream, stream->getL
ength())); |
| 387 SkAutoTDelete<SkImageGenerator> gen(SkCodecImageGenerator::NewFromEncode
dCodec(fullData)); | 322 SkAutoTDelete<SkImageGenerator> gen(SkCodecImageGenerator::NewFromEncode
dCodec(fullData)); |
| 388 SkBitmap bm; | 323 SkBitmap bm; |
| 389 bm.allocPixels(info); | 324 bm.allocPixels(info); |
| 390 SkAutoLockPixels autoLockPixels(bm); | 325 SkAutoLockPixels autoLockPixels(bm); |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 902 SkAutoTUnref<SkData> data(SkData::NewFromFileName(fullPath.c_str())); | 837 SkAutoTUnref<SkData> data(SkData::NewFromFileName(fullPath.c_str())); |
| 903 if (!data) { | 838 if (!data) { |
| 904 SkDebugf("Missing resource '%s'\n", path); | 839 SkDebugf("Missing resource '%s'\n", path); |
| 905 return; | 840 return; |
| 906 } | 841 } |
| 907 | 842 |
| 908 // The limit is less than webp needs to peek or read. | 843 // The limit is less than webp needs to peek or read. |
| 909 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(new LimitedPeekingMemStr
eam(data, 25))); | 844 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(new LimitedPeekingMemStr
eam(data, 25))); |
| 910 REPORTER_ASSERT(r, codec); | 845 REPORTER_ASSERT(r, codec); |
| 911 | 846 |
| 912 test_info(r, codec, codec->getInfo(), SkCodec::kSuccess, nullptr); | 847 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr); |
| 913 | 848 |
| 914 // Similarly, a stream which does not peek should still succeed. | 849 // Similarly, a stream which does not peek should still succeed. |
| 915 codec.reset(SkCodec::NewFromStream(new LimitedPeekingMemStream(data, 0))); | 850 codec.reset(SkCodec::NewFromStream(new LimitedPeekingMemStream(data, 0))); |
| 916 REPORTER_ASSERT(r, codec); | 851 REPORTER_ASSERT(r, codec); |
| 917 | 852 |
| 918 test_info(r, codec, codec->getInfo(), SkCodec::kSuccess, nullptr); | 853 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr); |
| 919 } | 854 } |
| 920 | 855 |
| 921 // SkCodec's wbmp decoder was initially more restrictive than SkImageDecoder. | 856 // SkCodec's wbmp decoder was initially more restrictive than SkImageDecoder. |
| 922 // It required the second byte to be zero. But SkImageDecoder allowed a couple | 857 // It required the second byte to be zero. But SkImageDecoder allowed a couple |
| 923 // of bits to be 1 (so long as they do not overlap with 0x9F). Test that | 858 // of bits to be 1 (so long as they do not overlap with 0x9F). Test that |
| 924 // SkCodec now supports an image with these bits set. | 859 // SkCodec now supports an image with these bits set. |
| 925 DEF_TEST(Codec_wbmp, r) { | 860 DEF_TEST(Codec_wbmp, r) { |
| 926 const char* path = "mandrill.wbmp"; | 861 const char* path = "mandrill.wbmp"; |
| 927 SkAutoTDelete<SkStream> stream(resource(path)); | 862 SkAutoTDelete<SkStream> stream(resource(path)); |
| 928 if (!stream) { | 863 if (!stream) { |
| 929 SkDebugf("Missing resource '%s'\n", path); | 864 SkDebugf("Missing resource '%s'\n", path); |
| 930 return; | 865 return; |
| 931 } | 866 } |
| 932 | 867 |
| 933 // Modify the stream to contain a second byte with some bits set. | 868 // Modify the stream to contain a second byte with some bits set. |
| 934 SkAutoTUnref<SkData> data(SkCopyStreamToData(stream)); | 869 SkAutoTUnref<SkData> data(SkCopyStreamToData(stream)); |
| 935 uint8_t* writeableData = static_cast<uint8_t*>(data->writable_data()); | 870 uint8_t* writeableData = static_cast<uint8_t*>(data->writable_data()); |
| 936 writeableData[1] = static_cast<uint8_t>(~0x9F); | 871 writeableData[1] = static_cast<uint8_t>(~0x9F); |
| 937 | 872 |
| 938 // SkImageDecoder supports this. | 873 // SkImageDecoder supports this. |
| 939 SkBitmap bitmap; | 874 SkBitmap bitmap; |
| 940 REPORTER_ASSERT(r, SkImageDecoder::DecodeMemory(data->data(), data->size(),
&bitmap)); | 875 REPORTER_ASSERT(r, SkImageDecoder::DecodeMemory(data->data(), data->size(),
&bitmap)); |
| 941 | 876 |
| 942 // So SkCodec should, too. | 877 // So SkCodec should, too. |
| 943 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data)); | 878 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data)); |
| 944 REPORTER_ASSERT(r, codec); | 879 REPORTER_ASSERT(r, codec); |
| 945 if (!codec) { | 880 if (!codec) { |
| 946 return; | 881 return; |
| 947 } | 882 } |
| 948 test_info(r, codec, codec->getInfo(), SkCodec::kSuccess, nullptr); | 883 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr); |
| 949 } | 884 } |
| 950 | 885 |
| 951 // wbmp images have a header that can be arbitrarily large, depending on the | 886 // wbmp images have a header that can be arbitrarily large, depending on the |
| 952 // size of the image. We cap the size at 65535, meaning we only need to look at | 887 // size of the image. We cap the size at 65535, meaning we only need to look at |
| 953 // 8 bytes to determine whether we can read the image. This is important | 888 // 8 bytes to determine whether we can read the image. This is important |
| 954 // because SkCodec only passes 14 bytes to SkWbmpCodec to determine whether the | 889 // because SkCodec only passes 14 bytes to SkWbmpCodec to determine whether the |
| 955 // image is a wbmp. | 890 // image is a wbmp. |
| 956 DEF_TEST(Codec_wbmp_max_size, r) { | 891 DEF_TEST(Codec_wbmp_max_size, r) { |
| 957 const unsigned char maxSizeWbmp[] = { 0x00, 0x00, // Header | 892 const unsigned char maxSizeWbmp[] = { 0x00, 0x00, // Header |
| 958 0x83, 0xFF, 0x7F, // W: 65535 | 893 0x83, 0xFF, 0x7F, // W: 65535 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 969 // Now test an image which is too big. Any image with a larger header (i.e. | 904 // Now test an image which is too big. Any image with a larger header (i.e. |
| 970 // has bigger width/height) is also too big. | 905 // has bigger width/height) is also too big. |
| 971 const unsigned char tooBigWbmp[] = { 0x00, 0x00, // Header | 906 const unsigned char tooBigWbmp[] = { 0x00, 0x00, // Header |
| 972 0x84, 0x80, 0x00, // W: 65536 | 907 0x84, 0x80, 0x00, // W: 65536 |
| 973 0x84, 0x80, 0x00 }; // H: 65536 | 908 0x84, 0x80, 0x00 }; // H: 65536 |
| 974 stream.reset(new SkMemoryStream(tooBigWbmp, sizeof(tooBigWbmp), false)); | 909 stream.reset(new SkMemoryStream(tooBigWbmp, sizeof(tooBigWbmp), false)); |
| 975 codec.reset(SkCodec::NewFromStream(stream.detach())); | 910 codec.reset(SkCodec::NewFromStream(stream.detach())); |
| 976 | 911 |
| 977 REPORTER_ASSERT(r, !codec); | 912 REPORTER_ASSERT(r, !codec); |
| 978 } | 913 } |
| OLD | NEW |