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 "SkBitmap.h" | 9 #include "SkBitmap.h" |
10 #include "SkCodec.h" | 10 #include "SkCodec.h" |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 rect.fLeft = rand->nextRangeU(0, w); | 68 rect.fLeft = rand->nextRangeU(0, w); |
69 rect.fTop = rand->nextRangeU(0, h); | 69 rect.fTop = rand->nextRangeU(0, h); |
70 rect.fRight = rand->nextRangeU(0, w); | 70 rect.fRight = rand->nextRangeU(0, w); |
71 rect.fBottom = rand->nextRangeU(0, h); | 71 rect.fBottom = rand->nextRangeU(0, h); |
72 rect.sort(); | 72 rect.sort(); |
73 } while (rect.isEmpty()); | 73 } while (rect.isEmpty()); |
74 return rect; | 74 return rect; |
75 } | 75 } |
76 | 76 |
77 static void test_codec(skiatest::Reporter* r, SkCodec* codec, SkBitmap& bm, cons
t SkImageInfo& info, | 77 static void test_codec(skiatest::Reporter* r, SkCodec* codec, SkBitmap& bm, cons
t SkImageInfo& info, |
78 const SkISize& size, bool supports565, SkMD5::Digest* digest, | 78 const SkISize& size, bool supports565, SkCodec::Result expectedResult, |
79 const SkMD5::Digest* goodDigest) { | 79 SkMD5::Digest* digest, const SkMD5::Digest* goodDigest) { |
| 80 |
80 REPORTER_ASSERT(r, info.dimensions() == size); | 81 REPORTER_ASSERT(r, info.dimensions() == size); |
81 bm.allocPixels(info); | 82 bm.allocPixels(info); |
82 SkAutoLockPixels autoLockPixels(bm); | 83 SkAutoLockPixels autoLockPixels(bm); |
83 | 84 |
84 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); | 85 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); |
85 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 86 REPORTER_ASSERT(r, result == expectedResult); |
86 | 87 |
87 md5(bm, digest); | 88 md5(bm, digest); |
88 if (goodDigest) { | 89 if (goodDigest) { |
89 REPORTER_ASSERT(r, *digest == *goodDigest); | 90 REPORTER_ASSERT(r, *digest == *goodDigest); |
90 } | 91 } |
91 | 92 |
92 { | 93 { |
93 // Test decoding to 565 | 94 // Test decoding to 565 |
94 SkImageInfo info565 = info.makeColorType(kRGB_565_SkColorType); | 95 SkImageInfo info565 = info.makeColorType(kRGB_565_SkColorType); |
95 SkCodec::Result expected = (supports565 && info.alphaType() == kOpaque_S
kAlphaType) ? | 96 SkCodec::Result expected565 = (supports565 && info.alphaType() == kOpaqu
e_SkAlphaType) ? |
96 SkCodec::kSuccess : SkCodec::kInvalidConversion; | 97 expectedResult : SkCodec::kInvalidConversion; |
97 test_info(r, codec, info565, expected, nullptr); | 98 test_info(r, codec, info565, expected565, nullptr); |
98 } | 99 } |
99 | 100 |
100 // Verify that re-decoding gives the same result. It is interesting to chec
k this after | 101 // Verify that re-decoding gives the same result. It is interesting to chec
k this after |
101 // a decode to 565, since choosing to decode to 565 may result in some of th
e decode | 102 // a decode to 565, since choosing to decode to 565 may result in some of th
e decode |
102 // options being modified. These options should return to their defaults on
another | 103 // options being modified. These options should return to their defaults on
another |
103 // decode to kN32, so the new digest should match the old digest. | 104 // decode to kN32, so the new digest should match the old digest. |
104 test_info(r, codec, info, SkCodec::kSuccess, digest); | 105 test_info(r, codec, info, expectedResult, digest); |
105 | 106 |
106 { | 107 { |
107 // Check alpha type conversions | 108 // Check alpha type conversions |
108 if (info.alphaType() == kOpaque_SkAlphaType) { | 109 if (info.alphaType() == kOpaque_SkAlphaType) { |
109 test_info(r, codec, info.makeAlphaType(kUnpremul_SkAlphaType), | 110 test_info(r, codec, info.makeAlphaType(kUnpremul_SkAlphaType), |
110 SkCodec::kInvalidConversion, nullptr); | 111 SkCodec::kInvalidConversion, nullptr); |
111 test_info(r, codec, info.makeAlphaType(kPremul_SkAlphaType), | 112 test_info(r, codec, info.makeAlphaType(kPremul_SkAlphaType), |
112 SkCodec::kInvalidConversion, nullptr); | 113 SkCodec::kInvalidConversion, nullptr); |
113 } else { | 114 } else { |
114 // Decoding to opaque should fail | 115 // Decoding to opaque should fail |
115 test_info(r, codec, info.makeAlphaType(kOpaque_SkAlphaType), | 116 test_info(r, codec, info.makeAlphaType(kOpaque_SkAlphaType), |
116 SkCodec::kInvalidConversion, nullptr); | 117 SkCodec::kInvalidConversion, nullptr); |
117 SkAlphaType otherAt = info.alphaType(); | 118 SkAlphaType otherAt = info.alphaType(); |
118 if (kPremul_SkAlphaType == otherAt) { | 119 if (kPremul_SkAlphaType == otherAt) { |
119 otherAt = kUnpremul_SkAlphaType; | 120 otherAt = kUnpremul_SkAlphaType; |
120 } else { | 121 } else { |
121 otherAt = kPremul_SkAlphaType; | 122 otherAt = kPremul_SkAlphaType; |
122 } | 123 } |
123 // The other non-opaque alpha type should always succeed, but not ma
tch. | 124 // The other non-opaque alpha type should always succeed, but not ma
tch. |
124 test_info(r, codec, info.makeAlphaType(otherAt), SkCodec::kSuccess,
nullptr); | 125 test_info(r, codec, info.makeAlphaType(otherAt), expectedResult, nul
lptr); |
125 } | 126 } |
126 } | 127 } |
127 } | 128 } |
128 | 129 |
129 static void check(skiatest::Reporter* r, | 130 static void check(skiatest::Reporter* r, |
130 const char path[], | 131 const char path[], |
131 SkISize size, | 132 SkISize size, |
132 bool supportsScanlineDecoding, | 133 bool supportsScanlineDecoding, |
133 bool supportsSubsetDecoding, | 134 bool supportsSubsetDecoding, |
134 bool supports565 = true) { | 135 bool supports565 = true, |
| 136 bool isIncomplete = false) { |
135 | 137 |
136 SkAutoTDelete<SkStream> stream(resource(path)); | 138 SkAutoTDelete<SkStream> stream(resource(path)); |
137 if (!stream) { | 139 if (!stream) { |
138 SkDebugf("Missing resource '%s'\n", path); | 140 SkDebugf("Missing resource '%s'\n", path); |
139 return; | 141 return; |
140 } | 142 } |
141 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach())); | 143 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach())); |
142 if (!codec) { | 144 if (!codec) { |
143 ERRORF(r, "Unable to decode '%s'", path); | 145 ERRORF(r, "Unable to decode '%s'", path); |
144 return; | 146 return; |
145 } | 147 } |
146 | 148 |
147 // Test full image decodes with SkCodec | 149 // Test full image decodes with SkCodec |
148 SkMD5::Digest codecDigest; | 150 SkMD5::Digest codecDigest; |
149 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); | 151 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
150 SkBitmap bm; | 152 SkBitmap bm; |
151 test_codec(r, codec, bm, info, size, supports565, &codecDigest, nullptr); | 153 SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput :
SkCodec::kSuccess; |
| 154 test_codec(r, codec, bm, info, size, supports565, expectedResult, &codecDige
st, nullptr); |
152 | 155 |
153 // Scanline decoding follows. | 156 // Scanline decoding follows. |
154 // Need to call startScanlineDecode() first. | 157 // Need to call startScanlineDecode() first. |
155 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 158 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
156 == SkCodec::kScanlineDecodingNotStarted); | 159 == 0); |
157 REPORTER_ASSERT(r, codec->skipScanlines(1) | 160 REPORTER_ASSERT(r, codec->skipScanlines(1) |
158 == SkCodec::kScanlineDecodingNotStarted); | 161 == 0); |
159 | 162 |
160 const SkCodec::Result startResult = codec->startScanlineDecode(info); | 163 const SkCodec::Result startResult = codec->startScanlineDecode(info); |
161 if (supportsScanlineDecoding) { | 164 if (supportsScanlineDecoding) { |
162 bm.eraseColor(SK_ColorYELLOW); | 165 bm.eraseColor(SK_ColorYELLOW); |
163 | 166 |
164 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess); | 167 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess); |
165 | 168 |
166 for (int y = 0; y < info.height(); y++) { | 169 for (int y = 0; y < info.height(); y++) { |
167 SkCodec::Result result = codec->getScanlines(bm.getAddr(0, y), 1, 0)
; | 170 const uint32_t lines = codec->getScanlines(bm.getAddr(0, y), 1, 0); |
168 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 171 if (!isIncomplete) { |
| 172 REPORTER_ASSERT(r, 1 == lines); |
| 173 } |
169 } | 174 } |
170 // verify that scanline decoding gives the same result. | 175 // verify that scanline decoding gives the same result. |
171 if (SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()) { | 176 if (SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()) { |
172 compare_to_good_digest(r, codecDigest, bm); | 177 compare_to_good_digest(r, codecDigest, bm); |
173 } | 178 } |
174 | 179 |
175 // Cannot continue to decode scanlines beyond the end | 180 // Cannot continue to decode scanlines beyond the end |
176 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 181 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
177 == SkCodec::kInvalidParameters); | 182 == 0); |
178 | 183 |
179 // Interrupting a scanline decode with a full decode starts from | 184 // Interrupting a scanline decode with a full decode starts from |
180 // scratch | 185 // scratch |
181 REPORTER_ASSERT(r, codec->startScanlineDecode(info) == SkCodec::kSuccess
); | 186 REPORTER_ASSERT(r, codec->startScanlineDecode(info) == SkCodec::kSuccess
); |
182 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 187 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
183 == SkCodec::kSuccess); | 188 == 1); |
184 REPORTER_ASSERT(r, codec->getPixels(bm.info(), bm.getPixels(), bm.rowByt
es()) | 189 REPORTER_ASSERT(r, codec->getPixels(bm.info(), bm.getPixels(), bm.rowByt
es()) |
185 == SkCodec::kSuccess); | 190 == expectedResult); |
186 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 191 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
187 == SkCodec::kScanlineDecodingNotStarted); | 192 == 0); |
188 REPORTER_ASSERT(r, codec->skipScanlines(1) | 193 REPORTER_ASSERT(r, codec->skipScanlines(1) |
189 == SkCodec::kScanlineDecodingNotStarted); | 194 == 0); |
190 } else { | 195 } else { |
191 REPORTER_ASSERT(r, startResult == SkCodec::kUnimplemented); | 196 REPORTER_ASSERT(r, startResult == SkCodec::kUnimplemented); |
192 } | 197 } |
193 | 198 |
194 // The rest of this function tests decoding subsets, and will decode an arbi
trary number of | 199 // The rest of this function tests decoding subsets, and will decode an arbi
trary number of |
195 // random subsets. | 200 // random subsets. |
196 // Do not attempt to decode subsets of an image of only once pixel, since th
ere is no | 201 // Do not attempt to decode subsets of an image of only once pixel, since th
ere is no |
197 // meaningful subset. | 202 // meaningful subset. |
198 if (size.width() * size.height() == 1) { | 203 if (size.width() * size.height() == 1) { |
199 return; | 204 return; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 return; | 239 return; |
235 } | 240 } |
236 SkAutoTDelete<SkCodec> codec(SkScaledCodec::NewFromStream(stream.detach(
))); | 241 SkAutoTDelete<SkCodec> codec(SkScaledCodec::NewFromStream(stream.detach(
))); |
237 if (!codec) { | 242 if (!codec) { |
238 ERRORF(r, "Unable to decode '%s'", path); | 243 ERRORF(r, "Unable to decode '%s'", path); |
239 return; | 244 return; |
240 } | 245 } |
241 | 246 |
242 SkBitmap bm; | 247 SkBitmap bm; |
243 SkMD5::Digest scaledCodecDigest; | 248 SkMD5::Digest scaledCodecDigest; |
244 test_codec(r, codec, bm, info, size, supports565, &scaledCodecDigest, &c
odecDigest); | 249 test_codec(r, codec, bm, info, size, supports565, expectedResult, &scale
dCodecDigest, |
| 250 &codecDigest); |
245 } | 251 } |
246 } | 252 } |
247 | 253 |
248 DEF_TEST(Codec, r) { | 254 DEF_TEST(Codec, r) { |
249 // WBMP | 255 // WBMP |
250 check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false); | 256 check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false); |
251 | 257 |
252 // WEBP | 258 // WEBP |
253 check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true); | 259 check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true); |
254 check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true); | 260 check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true); |
(...skipping 29 matching lines...) Expand all Loading... |
284 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false); | 290 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false); |
285 check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false); | 291 check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false); |
286 check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false); | 292 check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false); |
287 check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false); | 293 check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false); |
288 check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false); | 294 check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false); |
289 check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false); | 295 check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false); |
290 check(r, "plane.png", SkISize::Make(250, 126), true, false); | 296 check(r, "plane.png", SkISize::Make(250, 126), true, false); |
291 check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false); | 297 check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false); |
292 check(r, "randPixels.png", SkISize::Make(8, 8), true, false); | 298 check(r, "randPixels.png", SkISize::Make(8, 8), true, false); |
293 check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false); | 299 check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false); |
| 300 // Incomplete Image |
| 301 check(r, "incomplete_images/android.png", SkISize::Make(1024, 1218), true, f
alse, true, true); |
294 } | 302 } |
295 | 303 |
296 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode | 304 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode |
297 DEF_TEST(Codec_stripes, r) { | 305 DEF_TEST(Codec_stripes, r) { |
298 const char * path = "plane_interlaced.png"; | 306 const char * path = "plane_interlaced.png"; |
299 SkAutoTDelete<SkStream> stream(resource(path)); | 307 SkAutoTDelete<SkStream> stream(resource(path)); |
300 if (!stream) { | 308 if (!stream) { |
301 SkDebugf("Missing resource '%s'\n", path); | 309 SkDebugf("Missing resource '%s'\n", path); |
302 } | 310 } |
303 | 311 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 SkTDivMod(height, numStripes, &stripeHeight, &remainingLines); | 345 SkTDivMod(height, numStripes, &stripeHeight, &remainingLines); |
338 | 346 |
339 bm.eraseColor(SK_ColorYELLOW); | 347 bm.eraseColor(SK_ColorYELLOW); |
340 | 348 |
341 result = codec->startScanlineDecode(info); | 349 result = codec->startScanlineDecode(info); |
342 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 350 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
343 | 351 |
344 // Odd stripes | 352 // Odd stripes |
345 for (int i = 1; i < numStripes; i += 2) { | 353 for (int i = 1; i < numStripes; i += 2) { |
346 // Skip the even stripes | 354 // Skip the even stripes |
347 result = codec->skipScanlines(stripeHeight); | 355 bool skipResult = codec->skipScanlines(stripeHeight); |
348 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 356 REPORTER_ASSERT(r, skipResult); |
349 | 357 |
350 result = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeig
ht, | 358 int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight),
stripeHeight, |
351 bm.rowBytes()); | 359 bm.rowBytes()); |
352 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 360 REPORTER_ASSERT(r, linesDecoded == stripeHeight); |
353 } | 361 } |
354 | 362 |
355 // Even stripes | 363 // Even stripes |
356 result = codec->startScanlineDecode(info); | 364 result = codec->startScanlineDecode(info); |
357 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 365 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
358 | 366 |
359 for (int i = 0; i < numStripes; i += 2) { | 367 for (int i = 0; i < numStripes; i += 2) { |
360 result = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeig
ht, | 368 int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight),
stripeHeight, |
361 bm.rowBytes()); | 369 bm.rowBytes()); |
362 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 370 REPORTER_ASSERT(r, linesDecoded == stripeHeight); |
363 | 371 |
364 // Skip the odd stripes | 372 // Skip the odd stripes |
365 if (i + 1 < numStripes) { | 373 if (i + 1 < numStripes) { |
366 result = codec->skipScanlines(stripeHeight); | 374 bool skipResult = codec->skipScanlines(stripeHeight); |
367 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 375 REPORTER_ASSERT(r, skipResult); |
368 } | 376 } |
369 } | 377 } |
370 | 378 |
371 // Remainder at the end | 379 // Remainder at the end |
372 if (remainingLines > 0) { | 380 if (remainingLines > 0) { |
373 result = codec->startScanlineDecode(info); | 381 result = codec->startScanlineDecode(info); |
374 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 382 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
375 | 383 |
376 result = codec->skipScanlines(height - remainingLines); | 384 bool skipResult = codec->skipScanlines(height - remainingLines); |
377 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 385 REPORTER_ASSERT(r, skipResult); |
378 | 386 |
379 result = codec->getScanlines(bm.getAddr(0, height - remainingLines), | 387 int linesDecoded = codec->getScanlines(bm.getAddr(0, height - remainingL
ines), |
380 remainingLines, bm.rowBytes()); | 388 remainingLines, bm.rowBytes()); |
381 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 389 REPORTER_ASSERT(r, linesDecoded == remainingLines); |
382 } | 390 } |
383 | 391 |
384 compare_to_good_digest(r, digest, bm); | 392 compare_to_good_digest(r, digest, bm); |
385 } | 393 } |
386 | 394 |
387 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_
t len) { | 395 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_
t len) { |
388 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals
e)); | 396 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals
e)); |
389 // We should not have gotten a codec. Bots should catch us if we leaked anyt
hing. | 397 // We should not have gotten a codec. Bots should catch us if we leaked anyt
hing. |
390 REPORTER_ASSERT(r, !codec); | 398 REPORTER_ASSERT(r, !codec); |
391 } | 399 } |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 530 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
523 result = decoder->startScanlineDecode( | 531 result = decoder->startScanlineDecode( |
524 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); | 532 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); |
525 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 533 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
526 } | 534 } |
527 | 535 |
528 DEF_TEST(Codec_Params, r) { | 536 DEF_TEST(Codec_Params, r) { |
529 test_invalid_parameters(r, "index8.png"); | 537 test_invalid_parameters(r, "index8.png"); |
530 test_invalid_parameters(r, "mandrill.wbmp"); | 538 test_invalid_parameters(r, "mandrill.wbmp"); |
531 } | 539 } |
OLD | NEW |