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 |