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 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1114 stream.reset(resource(path)); | 1099 stream.reset(resource(path)); |
1115 codec.reset(SkCodec::NewFromStream(stream.release())); | 1100 codec.reset(SkCodec::NewFromStream(stream.release())); |
1116 SkBitmap bm2; | 1101 SkBitmap bm2; |
1117 bm2.allocPixels(codec->getInfo()); | 1102 bm2.allocPixels(codec->getInfo()); |
1118 result = codec->getPixels(codec->getInfo(), bm2.getPixels(), bm2.rowBytes())
; | 1103 result = codec->getPixels(codec->getInfo(), bm2.getPixels(), bm2.rowBytes())
; |
1119 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1104 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
1120 check_round_trip(r, bm2); | 1105 check_round_trip(r, bm2); |
1121 } | 1106 } |
1122 | 1107 |
1123 static void test_conversion_possible(skiatest::Reporter* r, const char* path, | 1108 static void test_conversion_possible(skiatest::Reporter* r, const char* path, |
1124 bool testScanlineDecoder) { | 1109 bool supportsScanlineDecoder, |
| 1110 bool supportsIncrementalDecoder) { |
1125 SkAutoTDelete<SkStream> stream(resource(path)); | 1111 SkAutoTDelete<SkStream> stream(resource(path)); |
1126 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); | 1112 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
1127 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); | 1113 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); |
1128 | 1114 |
1129 SkBitmap bm; | 1115 SkBitmap bm; |
1130 bm.allocPixels(infoF16); | 1116 bm.allocPixels(infoF16); |
1131 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt
es()); | 1117 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt
es()); |
1132 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | 1118 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
1133 if (testScanlineDecoder) { | 1119 |
1134 result = codec->startScanlineDecode(infoF16); | 1120 result = codec->startScanlineDecode(infoF16); |
| 1121 if (supportsScanlineDecoder) { |
1135 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | 1122 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
| 1123 } else { |
| 1124 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
| 1125 } |
| 1126 |
| 1127 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes(
)); |
| 1128 if (supportsIncrementalDecoder) { |
| 1129 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
| 1130 } else { |
| 1131 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
1136 } | 1132 } |
1137 | 1133 |
1138 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); | 1134 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); |
1139 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); | 1135 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); |
1140 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1136 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
1141 if (testScanlineDecoder) { | 1137 result = codec->startScanlineDecode(infoF16); |
1142 result = codec->startScanlineDecode(infoF16); | 1138 if (supportsScanlineDecoder) { |
1143 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1139 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1140 } else { |
| 1141 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
| 1142 } |
| 1143 |
| 1144 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes(
)); |
| 1145 if (supportsIncrementalDecoder) { |
| 1146 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1147 } else { |
| 1148 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); |
1144 } | 1149 } |
1145 } | 1150 } |
1146 | 1151 |
1147 DEF_TEST(Codec_F16ConversionPossible, r) { | 1152 DEF_TEST(Codec_F16ConversionPossible, r) { |
1148 test_conversion_possible(r, "color_wheel.webp", false); | 1153 test_conversion_possible(r, "color_wheel.webp", false, false); |
1149 test_conversion_possible(r, "mandrill_512_q075.jpg", true); | 1154 test_conversion_possible(r, "mandrill_512_q075.jpg", true, false); |
1150 test_conversion_possible(r, "yellow_rose.png", true); | 1155 test_conversion_possible(r, "yellow_rose.png", false, true); |
1151 } | 1156 } |
| 1157 |
| 1158 // Only rewinds up to a limit. |
| 1159 class LimitedRewindingStream : public SkStream { |
| 1160 public: |
| 1161 static SkStream* Make(const char path[], size_t limit) { |
| 1162 SkStream* stream = resource(path); |
| 1163 if (!stream) { |
| 1164 return nullptr; |
| 1165 } |
| 1166 return new LimitedRewindingStream(stream, limit); |
| 1167 } |
| 1168 |
| 1169 size_t read(void* buffer, size_t size) override { |
| 1170 const size_t bytes = fStream->read(buffer, size); |
| 1171 fPosition += bytes; |
| 1172 return bytes; |
| 1173 } |
| 1174 |
| 1175 bool isAtEnd() const override { |
| 1176 return fStream->isAtEnd(); |
| 1177 } |
| 1178 |
| 1179 bool rewind() override { |
| 1180 if (fPosition <= fLimit && fStream->rewind()) { |
| 1181 fPosition = 0; |
| 1182 return true; |
| 1183 } |
| 1184 |
| 1185 return false; |
| 1186 } |
| 1187 |
| 1188 private: |
| 1189 SkAutoTDelete<SkStream> fStream; |
| 1190 const size_t fLimit; |
| 1191 size_t fPosition; |
| 1192 |
| 1193 LimitedRewindingStream(SkStream* stream, size_t limit) |
| 1194 : fStream(stream) |
| 1195 , fLimit(limit) |
| 1196 , fPosition(0) |
| 1197 { |
| 1198 SkASSERT(fStream); |
| 1199 } |
| 1200 }; |
| 1201 |
| 1202 DEF_TEST(Codec_fallBack, r) { |
| 1203 // SkAndroidCodec needs to be able to fall back to scanline decoding |
| 1204 // if incremental decoding does not work. Make sure this does not |
| 1205 // require a rewind. |
| 1206 |
| 1207 // Formats that currently do not support incremental decoding |
| 1208 auto files = { |
| 1209 "box.gif", |
| 1210 "CMYK.jpg", |
| 1211 "color_wheel.ico", |
| 1212 "mandrill.wbmp", |
| 1213 "randPixels.bmp", |
| 1214 }; |
| 1215 for (auto file : files) { |
| 1216 SkStream* stream = LimitedRewindingStream::Make(file, 14); |
| 1217 if (!stream) { |
| 1218 SkDebugf("Missing resources (%s). Set --resourcePath.\n", file); |
| 1219 return; |
| 1220 } |
| 1221 |
| 1222 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream)); |
| 1223 if (!codec) { |
| 1224 ERRORF(r, "Failed to create codec for %s,", file); |
| 1225 continue; |
| 1226 } |
| 1227 |
| 1228 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
| 1229 SkBitmap bm; |
| 1230 bm.allocPixels(info); |
| 1231 |
| 1232 if (SkCodec::kUnimplemented != codec->startIncrementalDecode(info, bm.ge
tPixels(), |
| 1233 bm.rowBytes())) { |
| 1234 ERRORF(r, "Is scanline decoding now implemented for %s?", file); |
| 1235 continue; |
| 1236 } |
| 1237 |
| 1238 // Scanline decoding should not require a rewind. |
| 1239 SkCodec::Result result = codec->startScanlineDecode(info); |
| 1240 if (SkCodec::kSuccess != result) { |
| 1241 ERRORF(r, "Scanline decoding failed for %s with %i", file, result); |
| 1242 } |
| 1243 } |
| 1244 } |
OLD | NEW |