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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 do { | 77 do { |
78 rect.fLeft = rand->nextRangeU(0, w); | 78 rect.fLeft = rand->nextRangeU(0, w); |
79 rect.fTop = rand->nextRangeU(0, h); | 79 rect.fTop = rand->nextRangeU(0, h); |
80 rect.fRight = rand->nextRangeU(0, w); | 80 rect.fRight = rand->nextRangeU(0, w); |
81 rect.fBottom = rand->nextRangeU(0, h); | 81 rect.fBottom = rand->nextRangeU(0, h); |
82 rect.sort(); | 82 rect.sort(); |
83 } while (rect.isEmpty()); | 83 } while (rect.isEmpty()); |
84 return rect; | 84 return rect; |
85 } | 85 } |
86 | 86 |
| 87 static void test_incremental_decode(skiatest::Reporter* r, SkCodec* codec, const
SkImageInfo& info, |
| 88 const SkMD5::Digest& goodDigest) { |
| 89 SkBitmap bm; |
| 90 bm.allocPixels(info); |
| 91 SkAutoLockPixels autoLockPixels(bm); |
| 92 |
| 93 REPORTER_ASSERT(r, SkCodec::kSuccess == codec->startIncrementalDecode(info,
bm.getPixels(), |
| 94 bm.row
Bytes())); |
| 95 |
| 96 REPORTER_ASSERT(r, SkCodec::kSuccess == codec->incrementalDecode()); |
| 97 |
| 98 compare_to_good_digest(r, goodDigest, bm); |
| 99 } |
| 100 |
| 101 // Test in stripes, similar to DM's kStripe_Mode |
| 102 static void test_in_stripes(skiatest::Reporter* r, SkCodec* codec, const SkImage
Info& info, |
| 103 const SkMD5::Digest& goodDigest) { |
| 104 SkBitmap bm; |
| 105 bm.allocPixels(info); |
| 106 bm.eraseColor(SK_ColorYELLOW); |
| 107 |
| 108 const int height = info.height(); |
| 109 // Note that if numStripes does not evenly divide height there will be an ex
tra |
| 110 // stripe. |
| 111 const int numStripes = 4; |
| 112 |
| 113 if (numStripes > height) { |
| 114 // Image is too small. |
| 115 return; |
| 116 } |
| 117 |
| 118 const int stripeHeight = height / numStripes; |
| 119 |
| 120 // Iterate through the image twice. Once to decode odd stripes, and once for
even. |
| 121 for (int oddEven = 1; oddEven >= 0; oddEven--) { |
| 122 for (int y = oddEven * stripeHeight; y < height; y += 2 * stripeHeight)
{ |
| 123 SkIRect subset = SkIRect::MakeLTRB(0, y, info.width(), |
| 124 SkTMin(y + stripeHeight, height))
; |
| 125 SkCodec::Options options; |
| 126 options.fSubset = ⊂ |
| 127 if (SkCodec::kSuccess != codec->startIncrementalDecode(info, bm.getA
ddr(0, y), |
| 128 bm.rowBytes(), &options)) { |
| 129 ERRORF(r, "failed to start incremental decode!\ttop: %i\tbottom%
i\n", |
| 130 subset.top(), subset.bottom()); |
| 131 return; |
| 132 } |
| 133 if (SkCodec::kSuccess != codec->incrementalDecode()) { |
| 134 ERRORF(r, "failed incremental decode starting from line %i\n", y
); |
| 135 return; |
| 136 } |
| 137 } |
| 138 } |
| 139 |
| 140 compare_to_good_digest(r, goodDigest, bm); |
| 141 } |
| 142 |
87 template<typename Codec> | 143 template<typename Codec> |
88 static void test_codec(skiatest::Reporter* r, Codec* codec, SkBitmap& bm, const
SkImageInfo& info, | 144 static void test_codec(skiatest::Reporter* r, Codec* codec, SkBitmap& bm, const
SkImageInfo& info, |
89 const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* dige
st, | 145 const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* dige
st, |
90 const SkMD5::Digest* goodDigest) { | 146 const SkMD5::Digest* goodDigest) { |
91 | 147 |
92 REPORTER_ASSERT(r, info.dimensions() == size); | 148 REPORTER_ASSERT(r, info.dimensions() == size); |
93 bm.allocPixels(info); | 149 bm.allocPixels(info); |
94 SkAutoLockPixels autoLockPixels(bm); | 150 SkAutoLockPixels autoLockPixels(bm); |
95 | 151 |
96 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); | 152 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 }; | 241 }; |
186 | 242 |
187 for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { | 243 for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { |
188 if (SkStrEndsWith(path, exts[i])) { | 244 if (SkStrEndsWith(path, exts[i])) { |
189 return true; | 245 return true; |
190 } | 246 } |
191 } | 247 } |
192 return false; | 248 return false; |
193 } | 249 } |
194 | 250 |
| 251 // FIXME: Break up this giant function |
195 static void check(skiatest::Reporter* r, | 252 static void check(skiatest::Reporter* r, |
196 const char path[], | 253 const char path[], |
197 SkISize size, | 254 SkISize size, |
198 bool supportsScanlineDecoding, | 255 bool supportsScanlineDecoding, |
199 bool supportsSubsetDecoding, | 256 bool supportsSubsetDecoding, |
200 bool supportsIncomplete = true) { | 257 bool supportsIncomplete, |
| 258 bool supportsNewScanlineDecoding = false) { |
201 | 259 |
202 SkAutoTDelete<SkStream> stream(resource(path)); | 260 SkAutoTDelete<SkStream> stream(resource(path)); |
203 if (!stream) { | 261 if (!stream) { |
204 SkDebugf("Missing resource '%s'\n", path); | 262 SkDebugf("Missing resource '%s'\n", path); |
205 return; | 263 return; |
206 } | 264 } |
207 | 265 |
208 SkAutoTDelete<SkCodec> codec(nullptr); | 266 SkAutoTDelete<SkCodec> codec(nullptr); |
209 bool isIncomplete = supportsIncomplete; | 267 bool isIncomplete = supportsIncomplete; |
210 if (isIncomplete) { | 268 if (isIncomplete) { |
211 size_t size = stream->getLength(); | 269 size_t size = stream->getLength(); |
212 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3))); | 270 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3))); |
213 codec.reset(SkCodec::NewFromData(data)); | 271 codec.reset(SkCodec::NewFromData(data)); |
214 } else { | 272 } else { |
215 codec.reset(SkCodec::NewFromStream(stream.release())); | 273 codec.reset(SkCodec::NewFromStream(stream.release())); |
216 } | 274 } |
217 if (!codec) { | 275 if (!codec) { |
218 ERRORF(r, "Unable to decode '%s'", path); | 276 ERRORF(r, "Unable to decode '%s'", path); |
219 return; | 277 return; |
220 } | 278 } |
221 | 279 |
222 // Test full image decodes with SkCodec | 280 // Test full image decodes with SkCodec |
223 SkMD5::Digest codecDigest; | 281 SkMD5::Digest codecDigest; |
224 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); | 282 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
225 SkBitmap bm; | 283 SkBitmap bm; |
226 SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput :
SkCodec::kSuccess; | 284 SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput :
SkCodec::kSuccess; |
227 test_codec(r, codec.get(), bm, info, size, expectedResult, &codecDigest, nul
lptr); | 285 test_codec(r, codec.get(), bm, info, size, expectedResult, &codecDigest, nul
lptr); |
228 | 286 |
229 // Scanline decoding follows. | 287 // Scanline decoding follows. |
| 288 |
| 289 if (supportsNewScanlineDecoding && !isIncomplete) { |
| 290 test_incremental_decode(r, codec, info, codecDigest); |
| 291 test_in_stripes(r, codec, info, codecDigest); |
| 292 } |
| 293 |
230 // Need to call startScanlineDecode() first. | 294 // Need to call startScanlineDecode() first. |
231 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 295 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) == 0); |
232 == 0); | 296 REPORTER_ASSERT(r, !codec->skipScanlines(1)); |
233 REPORTER_ASSERT(r, codec->skipScanlines(1) | |
234 == 0); | |
235 | |
236 const SkCodec::Result startResult = codec->startScanlineDecode(info); | 297 const SkCodec::Result startResult = codec->startScanlineDecode(info); |
237 if (supportsScanlineDecoding) { | 298 if (supportsScanlineDecoding) { |
238 bm.eraseColor(SK_ColorYELLOW); | 299 bm.eraseColor(SK_ColorYELLOW); |
239 | 300 |
240 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess); | 301 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess); |
241 | 302 |
242 for (int y = 0; y < info.height(); y++) { | 303 for (int y = 0; y < info.height(); y++) { |
243 const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0); | 304 const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0); |
244 if (!isIncomplete) { | 305 if (!isIncomplete) { |
245 REPORTER_ASSERT(r, 1 == lines); | 306 REPORTER_ASSERT(r, 1 == lines); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 // Webp is the only codec that supports subsets, and it will have mo
dified the subset | 381 // Webp is the only codec that supports subsets, and it will have mo
dified the subset |
321 // to have even left/top. | 382 // to have even left/top. |
322 REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTo
p)); | 383 REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTo
p)); |
323 } else { | 384 } else { |
324 // No subsets will work. | 385 // No subsets will work. |
325 REPORTER_ASSERT(r, result == SkCodec::kUnimplemented); | 386 REPORTER_ASSERT(r, result == SkCodec::kUnimplemented); |
326 } | 387 } |
327 } | 388 } |
328 | 389 |
329 // SkAndroidCodec tests | 390 // SkAndroidCodec tests |
330 if (supportsScanlineDecoding || supportsSubsetDecoding) { | 391 if (supportsScanlineDecoding || supportsSubsetDecoding || supportsNewScanlin
eDecoding) { |
331 | 392 |
332 SkAutoTDelete<SkStream> stream(resource(path)); | 393 SkAutoTDelete<SkStream> stream(resource(path)); |
333 if (!stream) { | 394 if (!stream) { |
334 SkDebugf("Missing resource '%s'\n", path); | 395 SkDebugf("Missing resource '%s'\n", path); |
335 return; | 396 return; |
336 } | 397 } |
337 | 398 |
338 SkAutoTDelete<SkAndroidCodec> androidCodec(nullptr); | 399 SkAutoTDelete<SkAndroidCodec> androidCodec(nullptr); |
339 if (isIncomplete) { | 400 if (isIncomplete) { |
340 size_t size = stream->getLength(); | 401 size_t size = stream->getLength(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 } | 439 } |
379 | 440 |
380 // If we've just tested incomplete decodes, let's run the same test again on
full decodes. | 441 // If we've just tested incomplete decodes, let's run the same test again on
full decodes. |
381 if (isIncomplete) { | 442 if (isIncomplete) { |
382 check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding, f
alse); | 443 check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding, f
alse); |
383 } | 444 } |
384 } | 445 } |
385 | 446 |
386 DEF_TEST(Codec, r) { | 447 DEF_TEST(Codec, r) { |
387 // WBMP | 448 // WBMP |
388 check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false); | 449 check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false, true); |
389 | 450 |
390 // WEBP | 451 // WEBP |
391 check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true); | 452 check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true, true); |
392 check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true); | 453 check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true, true); |
393 check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true); | 454 check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true, true); |
394 | 455 |
395 // BMP | 456 // BMP |
396 check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false); | 457 check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false, true); |
397 check(r, "rle.bmp", SkISize::Make(320, 240), true, false); | 458 check(r, "rle.bmp", SkISize::Make(320, 240), true, false, true); |
398 | 459 |
399 // ICO | 460 // ICO |
400 // FIXME: We are not ready to test incomplete ICOs | 461 // FIXME: We are not ready to test incomplete ICOs |
401 // These two tests examine interestingly different behavior: | 462 // These two tests examine interestingly different behavior: |
402 // Decodes an embedded BMP image | 463 // Decodes an embedded BMP image |
403 check(r, "color_wheel.ico", SkISize::Make(128, 128), true, false, false); | 464 check(r, "color_wheel.ico", SkISize::Make(128, 128), true, false, false); |
404 // Decodes an embedded PNG image | 465 // Decodes an embedded PNG image |
405 check(r, "google_chrome.ico", SkISize::Make(256, 256), true, false, false); | 466 check(r, "google_chrome.ico", SkISize::Make(256, 256), false, false, false,
true); |
406 | 467 |
407 // GIF | 468 // GIF |
408 // FIXME: We are not ready to test incomplete GIFs | 469 // FIXME: We are not ready to test incomplete GIFs |
409 check(r, "box.gif", SkISize::Make(200, 55), true, false, false); | 470 check(r, "box.gif", SkISize::Make(200, 55), true, false, false); |
410 check(r, "color_wheel.gif", SkISize::Make(128, 128), true, false, false); | 471 check(r, "color_wheel.gif", SkISize::Make(128, 128), true, false, false); |
411 // randPixels.gif is too small to test incomplete | 472 // randPixels.gif is too small to test incomplete |
412 check(r, "randPixels.gif", SkISize::Make(8, 8), true, false, false); | 473 check(r, "randPixels.gif", SkISize::Make(8, 8), true, false, false); |
413 | 474 |
414 // JPG | 475 // JPG |
415 check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false); | 476 check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false, true); |
416 check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false); | 477 check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false, true); |
417 // grayscale.jpg is too small to test incomplete | 478 // grayscale.jpg is too small to test incomplete |
418 check(r, "grayscale.jpg", SkISize::Make(128, 128), true, false, false); | 479 check(r, "grayscale.jpg", SkISize::Make(128, 128), true, false, false); |
419 check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false); | 480 check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false, true
); |
420 // randPixels.jpg is too small to test incomplete | 481 // randPixels.jpg is too small to test incomplete |
421 check(r, "randPixels.jpg", SkISize::Make(8, 8), true, false, false); | 482 check(r, "randPixels.jpg", SkISize::Make(8, 8), true, false, false); |
422 | 483 |
423 // PNG | 484 // PNG |
424 check(r, "arrow.png", SkISize::Make(187, 312), true, false, false); | 485 check(r, "arrow.png", SkISize::Make(187, 312), false, false, true, true); |
425 check(r, "baby_tux.png", SkISize::Make(240, 246), true, false, false); | 486 check(r, "baby_tux.png", SkISize::Make(240, 246), false, false, true, true); |
426 check(r, "color_wheel.png", SkISize::Make(128, 128), true, false, false); | 487 check(r, "color_wheel.png", SkISize::Make(128, 128), false, false, true, tru
e); |
427 check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), true, fals
e, false); | 488 // half-transparent-white-pixel.png is too small to test incomplete |
428 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false, false); | 489 check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), false, fal
se, false, true); |
429 check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false, false); | 490 check(r, "mandrill_128.png", SkISize::Make(128, 128), false, false, true, tr
ue); |
430 check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false, false); | 491 check(r, "mandrill_16.png", SkISize::Make(16, 16), false, false, true, true)
; |
431 check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false, false); | 492 check(r, "mandrill_256.png", SkISize::Make(256, 256), false, false, true, tr
ue); |
432 check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false, false); | 493 check(r, "mandrill_32.png", SkISize::Make(32, 32), false, false, true, true)
; |
433 check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false, false); | 494 check(r, "mandrill_512.png", SkISize::Make(512, 512), false, false, true, tr
ue); |
434 check(r, "plane.png", SkISize::Make(250, 126), true, false, false); | 495 check(r, "mandrill_64.png", SkISize::Make(64, 64), false, false, true, true)
; |
435 // FIXME: We are not ready to test incomplete interlaced pngs | 496 check(r, "plane.png", SkISize::Make(250, 126), false, false, true, true); |
436 check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false, false
); | 497 check(r, "plane_interlaced.png", SkISize::Make(250, 126), false, false, true
, true); |
437 check(r, "randPixels.png", SkISize::Make(8, 8), true, false, false); | 498 check(r, "randPixels.png", SkISize::Make(8, 8), false, false, true, true); |
438 check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false, false); | 499 check(r, "yellow_rose.png", SkISize::Make(400, 301), false, false, true, tru
e); |
439 | 500 |
440 // RAW | 501 // RAW |
441 // Disable RAW tests for Win32. | 502 // Disable RAW tests for Win32. |
442 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) | 503 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) |
443 check(r, "sample_1mp.dng", SkISize::Make(600, 338), false, false, false); | 504 check(r, "sample_1mp.dng", SkISize::Make(600, 338), false, false, false); |
444 check(r, "sample_1mp_rotated.dng", SkISize::Make(600, 338), false, false, fa
lse); | 505 check(r, "sample_1mp_rotated.dng", SkISize::Make(600, 338), false, false, fa
lse); |
445 check(r, "dng_with_preview.dng", SkISize::Make(600, 338), true, false, false
); | 506 check(r, "dng_with_preview.dng", SkISize::Make(600, 338), true, false, false
); |
446 #endif | 507 #endif |
447 } | 508 } |
448 | 509 |
449 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode | |
450 DEF_TEST(Codec_stripes, r) { | |
451 const char * path = "plane_interlaced.png"; | |
452 SkAutoTDelete<SkStream> stream(resource(path)); | |
453 if (!stream) { | |
454 SkDebugf("Missing resource '%s'\n", path); | |
455 } | |
456 | |
457 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); | |
458 REPORTER_ASSERT(r, codec); | |
459 | |
460 if (!codec) { | |
461 return; | |
462 } | |
463 | |
464 switch (codec->getScanlineOrder()) { | |
465 case SkCodec::kBottomUp_SkScanlineOrder: | |
466 case SkCodec::kOutOfOrder_SkScanlineOrder: | |
467 ERRORF(r, "This scanline order will not match the original."); | |
468 return; | |
469 default: | |
470 break; | |
471 } | |
472 | |
473 // Baseline for what the image should look like, using N32. | |
474 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); | |
475 | |
476 SkBitmap bm; | |
477 bm.allocPixels(info); | |
478 SkAutoLockPixels autoLockPixels(bm); | |
479 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); | |
480 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
481 | |
482 SkMD5::Digest digest; | |
483 md5(bm, &digest); | |
484 | |
485 // Now decode in stripes | |
486 const int height = info.height(); | |
487 const int numStripes = 4; | |
488 int stripeHeight; | |
489 int remainingLines; | |
490 SkTDivMod(height, numStripes, &stripeHeight, &remainingLines); | |
491 | |
492 bm.eraseColor(SK_ColorYELLOW); | |
493 | |
494 result = codec->startScanlineDecode(info); | |
495 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
496 | |
497 // Odd stripes | |
498 for (int i = 1; i < numStripes; i += 2) { | |
499 // Skip the even stripes | |
500 bool skipResult = codec->skipScanlines(stripeHeight); | |
501 REPORTER_ASSERT(r, skipResult); | |
502 | |
503 int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight),
stripeHeight, | |
504 bm.rowBytes()); | |
505 REPORTER_ASSERT(r, linesDecoded == stripeHeight); | |
506 } | |
507 | |
508 // Even stripes | |
509 result = codec->startScanlineDecode(info); | |
510 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
511 | |
512 for (int i = 0; i < numStripes; i += 2) { | |
513 int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight),
stripeHeight, | |
514 bm.rowBytes()); | |
515 REPORTER_ASSERT(r, linesDecoded == stripeHeight); | |
516 | |
517 // Skip the odd stripes | |
518 if (i + 1 < numStripes) { | |
519 bool skipResult = codec->skipScanlines(stripeHeight); | |
520 REPORTER_ASSERT(r, skipResult); | |
521 } | |
522 } | |
523 | |
524 // Remainder at the end | |
525 if (remainingLines > 0) { | |
526 result = codec->startScanlineDecode(info); | |
527 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
528 | |
529 bool skipResult = codec->skipScanlines(height - remainingLines); | |
530 REPORTER_ASSERT(r, skipResult); | |
531 | |
532 int linesDecoded = codec->getScanlines(bm.getAddr(0, height - remainingL
ines), | |
533 remainingLines, bm.rowBytes()); | |
534 REPORTER_ASSERT(r, linesDecoded == remainingLines); | |
535 } | |
536 | |
537 compare_to_good_digest(r, digest, bm); | |
538 } | |
539 | |
540 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_
t len) { | 510 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_
t len) { |
541 // Neither of these calls should return a codec. Bots should catch us if we
leaked anything. | 511 // Neither of these calls should return a codec. Bots should catch us if we
leaked anything. |
542 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals
e)); | 512 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals
e)); |
543 REPORTER_ASSERT(r, !codec); | 513 REPORTER_ASSERT(r, !codec); |
544 | 514 |
545 SkAndroidCodec* androidCodec = | 515 SkAndroidCodec* androidCodec = |
546 SkAndroidCodec::NewFromStream(new SkMemoryStream(stream, len, false)
); | 516 SkAndroidCodec::NewFromStream(new SkMemoryStream(stream, len, false)
); |
547 REPORTER_ASSERT(r, !androidCodec); | 517 REPORTER_ASSERT(r, !androidCodec); |
548 } | 518 } |
549 | 519 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); | 642 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); |
673 } | 643 } |
674 | 644 |
675 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { | 645 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { |
676 SkAutoTDelete<SkStream> stream(resource(path)); | 646 SkAutoTDelete<SkStream> stream(resource(path)); |
677 if (!stream) { | 647 if (!stream) { |
678 SkDebugf("Missing resource '%s'\n", path); | 648 SkDebugf("Missing resource '%s'\n", path); |
679 return; | 649 return; |
680 } | 650 } |
681 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release())); | 651 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release())); |
| 652 if (!decoder) { |
| 653 SkDebugf("Missing codec for %s\n", path); |
| 654 return; |
| 655 } |
| 656 |
| 657 const SkImageInfo info = decoder->getInfo().makeColorType(kIndex_8_SkColorTy
pe); |
682 | 658 |
683 // This should return kSuccess because kIndex8 is supported. | 659 // This should return kSuccess because kIndex8 is supported. |
684 SkPMColor colorStorage[256]; | 660 SkPMColor colorStorage[256]; |
685 int colorCount; | 661 int colorCount; |
686 SkCodec::Result result = decoder->startScanlineDecode( | 662 SkCodec::Result result = decoder->startScanlineDecode(info, nullptr, colorSt
orage, |
687 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt
orage, &colorCount); | 663 &colorCount); |
688 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 664 if (SkCodec::kSuccess == result) { |
689 // The rest of the test is uninteresting if kIndex8 is not supported | 665 // This should return kInvalidParameters because, in kIndex_8 mode, we m
ust pass in a valid |
690 if (SkCodec::kSuccess != result) { | 666 // colorPtr and a valid colorCountPtr. |
| 667 result = decoder->startScanlineDecode(info, nullptr, nullptr, nullptr); |
| 668 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 669 result = decoder->startScanlineDecode(info); |
| 670 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 671 } else if (SkCodec::kUnimplemented == result) { |
| 672 // New method should be supported: |
| 673 SkBitmap bm; |
| 674 sk_sp<SkColorTable> colorTable(new SkColorTable(colorStorage, 256)); |
| 675 bm.allocPixels(info, nullptr, colorTable.get()); |
| 676 result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowByt
es(), nullptr, |
| 677 colorStorage, &colorCount); |
| 678 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 679 result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowByt
es()); |
| 680 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 681 } else { |
| 682 // The test is uninteresting if kIndex8 is not supported |
| 683 ERRORF(r, "Should not call test_invalid_parameters for non-Index8 file:
%s\n", path); |
691 return; | 684 return; |
692 } | 685 } |
693 | 686 |
694 // This should return kInvalidParameters because, in kIndex_8 mode, we must
pass in a valid | |
695 // colorPtr and a valid colorCountPtr. | |
696 result = decoder->startScanlineDecode( | |
697 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, nullptr
, nullptr); | |
698 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | |
699 result = decoder->startScanlineDecode( | |
700 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); | |
701 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | |
702 } | 687 } |
703 | 688 |
704 DEF_TEST(Codec_Params, r) { | 689 DEF_TEST(Codec_Params, r) { |
705 test_invalid_parameters(r, "index8.png"); | 690 test_invalid_parameters(r, "index8.png"); |
706 test_invalid_parameters(r, "mandrill.wbmp"); | 691 test_invalid_parameters(r, "mandrill.wbmp"); |
707 } | 692 } |
708 | 693 |
709 static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t
len) { | 694 static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t
len) { |
710 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); | 695 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); |
711 if (!sk_stream->write(data, len)) { | 696 if (!sk_stream->write(data, len)) { |
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1171 codec.reset(SkCodec::NewFromStream(stream.release())); | 1156 codec.reset(SkCodec::NewFromStream(stream.release())); |
1172 | 1157 |
1173 for (SkAlphaType alphaType : alphaTypes) { | 1158 for (SkAlphaType alphaType : alphaTypes) { |
1174 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType) | 1159 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType) |
1175 .makeColorSpace(nullptr); | 1160 .makeColorSpace(nullptr); |
1176 check_round_trip(r, codec.get(), newInfo); | 1161 check_round_trip(r, codec.get(), newInfo); |
1177 } | 1162 } |
1178 } | 1163 } |
1179 | 1164 |
1180 static void test_conversion_possible(skiatest::Reporter* r, const char* path, | 1165 static void test_conversion_possible(skiatest::Reporter* r, const char* path, |
1181 bool testScanlineDecoder) { | 1166 bool supportsScanlineDecoder, |
| 1167 bool supportsIncrementalDecoder) { |
1182 SkAutoTDelete<SkStream> stream(resource(path)); | 1168 SkAutoTDelete<SkStream> stream(resource(path)); |
1183 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); | 1169 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
1184 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); | 1170 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); |
1185 | 1171 |
1186 SkBitmap bm; | 1172 SkBitmap bm; |
1187 bm.allocPixels(infoF16); | 1173 bm.allocPixels(infoF16); |
1188 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt
es()); | 1174 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt
es()); |
1189 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | 1175 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
1190 if (testScanlineDecoder) { | 1176 |
1191 result = codec->startScanlineDecode(infoF16); | 1177 result = codec->startScanlineDecode(infoF16); |
| 1178 if (supportsScanlineDecoder) { |
1192 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | 1179 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
| 1180 } else { |
| 1181 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
| 1182 } |
| 1183 |
| 1184 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes(
)); |
| 1185 if (supportsIncrementalDecoder) { |
| 1186 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
| 1187 } else { |
| 1188 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
1193 } | 1189 } |
1194 | 1190 |
1195 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); | 1191 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); |
1196 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); | 1192 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); |
1197 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1193 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
1198 if (testScanlineDecoder) { | 1194 result = codec->startScanlineDecode(infoF16); |
1199 result = codec->startScanlineDecode(infoF16); | 1195 if (supportsScanlineDecoder) { |
1200 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1196 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1197 } else { |
| 1198 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
| 1199 } |
| 1200 |
| 1201 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes(
)); |
| 1202 if (supportsIncrementalDecoder) { |
| 1203 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1204 } else { |
| 1205 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
1201 } | 1206 } |
1202 } | 1207 } |
1203 | 1208 |
1204 DEF_TEST(Codec_F16ConversionPossible, r) { | 1209 DEF_TEST(Codec_F16ConversionPossible, r) { |
1205 test_conversion_possible(r, "color_wheel.webp", false); | 1210 test_conversion_possible(r, "color_wheel.webp", false, false); |
1206 test_conversion_possible(r, "mandrill_512_q075.jpg", true); | 1211 test_conversion_possible(r, "mandrill_512_q075.jpg", true, false); |
1207 test_conversion_possible(r, "yellow_rose.png", true); | 1212 test_conversion_possible(r, "yellow_rose.png", false, true); |
1208 } | 1213 } |
| 1214 |
| 1215 // Only rewinds up to a limit. |
| 1216 class LimitedRewindingStream : public SkStream { |
| 1217 public: |
| 1218 static SkStream* Make(const char path[], size_t limit) { |
| 1219 SkStream* stream = resource(path); |
| 1220 if (!stream) { |
| 1221 return nullptr; |
| 1222 } |
| 1223 return new LimitedRewindingStream(stream, limit); |
| 1224 } |
| 1225 |
| 1226 size_t read(void* buffer, size_t size) override { |
| 1227 const size_t bytes = fStream->read(buffer, size); |
| 1228 fPosition += bytes; |
| 1229 return bytes; |
| 1230 } |
| 1231 |
| 1232 bool isAtEnd() const override { |
| 1233 return fStream->isAtEnd(); |
| 1234 } |
| 1235 |
| 1236 bool rewind() override { |
| 1237 if (fPosition <= fLimit && fStream->rewind()) { |
| 1238 fPosition = 0; |
| 1239 return true; |
| 1240 } |
| 1241 |
| 1242 return false; |
| 1243 } |
| 1244 |
| 1245 private: |
| 1246 SkAutoTDelete<SkStream> fStream; |
| 1247 const size_t fLimit; |
| 1248 size_t fPosition; |
| 1249 |
| 1250 LimitedRewindingStream(SkStream* stream, size_t limit) |
| 1251 : fStream(stream) |
| 1252 , fLimit(limit) |
| 1253 , fPosition(0) |
| 1254 { |
| 1255 SkASSERT(fStream); |
| 1256 } |
| 1257 }; |
| 1258 |
| 1259 DEF_TEST(Codec_fallBack, r) { |
| 1260 // SkAndroidCodec needs to be able to fall back to scanline decoding |
| 1261 // if incremental decoding does not work. Make sure this does not |
| 1262 // require a rewind. |
| 1263 |
| 1264 // Formats that currently do not support incremental decoding |
| 1265 auto files = { |
| 1266 "box.gif", |
| 1267 "CMYK.jpg", |
| 1268 "color_wheel.ico", |
| 1269 "mandrill.wbmp", |
| 1270 "randPixels.bmp", |
| 1271 }; |
| 1272 for (auto file : files) { |
| 1273 SkStream* stream = LimitedRewindingStream::Make(file, 14); |
| 1274 if (!stream) { |
| 1275 SkDebugf("Missing resources (%s). Set --resourcePath.\n", file); |
| 1276 return; |
| 1277 } |
| 1278 |
| 1279 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream)); |
| 1280 if (!codec) { |
| 1281 ERRORF(r, "Failed to create codec for %s,", file); |
| 1282 continue; |
| 1283 } |
| 1284 |
| 1285 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
| 1286 SkBitmap bm; |
| 1287 bm.allocPixels(info); |
| 1288 |
| 1289 if (SkCodec::kUnimplemented != codec->startIncrementalDecode(info, bm.ge
tPixels(), |
| 1290 bm.rowBytes())) { |
| 1291 ERRORF(r, "Is scanline decoding now implemented for %s?", file); |
| 1292 continue; |
| 1293 } |
| 1294 |
| 1295 // Scanline decoding should not require a rewind. |
| 1296 SkCodec::Result result = codec->startScanlineDecode(info); |
| 1297 if (SkCodec::kSuccess != result) { |
| 1298 ERRORF(r, "Scanline decoding failed for %s with %i", file, result); |
| 1299 } |
| 1300 } |
| 1301 } |
OLD | NEW |