Chromium Code Reviews| 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 REPORTER_ASSERT(r, bufferedStream); | 433 REPORTER_ASSERT(r, bufferedStream); |
| 373 codec.reset(SkCodec::NewFromStream(bufferedStream)); | 434 codec.reset(SkCodec::NewFromStream(bufferedStream)); |
| 374 REPORTER_ASSERT(r, codec); | 435 REPORTER_ASSERT(r, codec); |
| 375 if (codec) { | 436 if (codec) { |
| 376 test_info(r, codec.get(), info, SkCodec::kSuccess, &codecDigest); | 437 test_info(r, codec.get(), info, SkCodec::kSuccess, &codecDigest); |
| 377 } | 438 } |
| 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, |
| 444 supportsNewScanlineDecoding); | |
| 383 } | 445 } |
| 384 } | 446 } |
| 385 | 447 |
| 386 DEF_TEST(Codec, r) { | 448 DEF_TEST(Codec, r) { |
| 387 // WBMP | 449 // WBMP |
| 388 check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false); | 450 check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false, true); |
| 389 | 451 |
| 390 // WEBP | 452 // WEBP |
| 391 check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true); | 453 check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true, true); |
| 392 check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true); | 454 check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true, true); |
| 393 check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true); | 455 check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true, true); |
| 394 | 456 |
| 395 // BMP | 457 // BMP |
| 396 check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false); | 458 check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false, true); |
| 397 check(r, "rle.bmp", SkISize::Make(320, 240), true, false); | 459 check(r, "rle.bmp", SkISize::Make(320, 240), true, false, true); |
| 398 | 460 |
| 399 // ICO | 461 // ICO |
| 400 // FIXME: We are not ready to test incomplete ICOs | 462 // FIXME: We are not ready to test incomplete ICOs |
| 401 // These two tests examine interestingly different behavior: | 463 // These two tests examine interestingly different behavior: |
| 402 // Decodes an embedded BMP image | 464 // Decodes an embedded BMP image |
| 403 check(r, "color_wheel.ico", SkISize::Make(128, 128), true, false, false); | 465 check(r, "color_wheel.ico", SkISize::Make(128, 128), true, false, false); |
| 404 // Decodes an embedded PNG image | 466 // Decodes an embedded PNG image |
| 405 check(r, "google_chrome.ico", SkISize::Make(256, 256), true, false, false); | 467 check(r, "google_chrome.ico", SkISize::Make(256, 256), false, false, false, true); |
| 406 | 468 |
| 407 // GIF | 469 // GIF |
| 408 // FIXME: We are not ready to test incomplete GIFs | 470 // FIXME: We are not ready to test incomplete GIFs |
| 409 check(r, "box.gif", SkISize::Make(200, 55), true, false, false); | 471 check(r, "box.gif", SkISize::Make(200, 55), true, false, false); |
| 410 check(r, "color_wheel.gif", SkISize::Make(128, 128), true, false, false); | 472 check(r, "color_wheel.gif", SkISize::Make(128, 128), true, false, false); |
| 411 // randPixels.gif is too small to test incomplete | 473 // randPixels.gif is too small to test incomplete |
| 412 check(r, "randPixels.gif", SkISize::Make(8, 8), true, false, false); | 474 check(r, "randPixels.gif", SkISize::Make(8, 8), true, false, false); |
| 413 | 475 |
| 414 // JPG | 476 // JPG |
| 415 check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false); | 477 check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false, true); |
| 416 check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false); | 478 check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false, true); |
| 417 // grayscale.jpg is too small to test incomplete | 479 // grayscale.jpg is too small to test incomplete |
| 418 check(r, "grayscale.jpg", SkISize::Make(128, 128), true, false, false); | 480 check(r, "grayscale.jpg", SkISize::Make(128, 128), true, false, false); |
| 419 check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false); | 481 check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false, true ); |
| 420 // randPixels.jpg is too small to test incomplete | 482 // randPixels.jpg is too small to test incomplete |
| 421 check(r, "randPixels.jpg", SkISize::Make(8, 8), true, false, false); | 483 check(r, "randPixels.jpg", SkISize::Make(8, 8), true, false, false); |
| 422 | 484 |
| 423 // PNG | 485 // PNG |
| 424 check(r, "arrow.png", SkISize::Make(187, 312), true, false, false); | 486 check(r, "arrow.png", SkISize::Make(187, 312), false, false, true, true); |
|
scroggo_chromium
2016/09/15 22:34:54
(Moving your comment to a spot relevant to my poin
msarett
2016/09/16 12:20:16
I think it's a fill() problem.
The problem I thou
| |
| 425 check(r, "baby_tux.png", SkISize::Make(240, 246), true, false, false); | 487 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); | 488 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); | 489 // half-transparent-white-pixel.png is too small to test incomplete |
| 428 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false, false); | 490 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); | 491 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); | 492 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); | 493 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); | 494 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); | 495 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); | 496 check(r, "mandrill_64.png", SkISize::Make(64, 64), false, false, true, true) ; |
| 435 // FIXME: We are not ready to test incomplete interlaced pngs | 497 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 ); | 498 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); | 499 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); | 500 check(r, "yellow_rose.png", SkISize::Make(400, 301), false, false, true, tru e); |
| 439 | 501 |
| 440 // RAW | 502 // RAW |
| 441 // Disable RAW tests for Win32. | 503 // Disable RAW tests for Win32. |
| 442 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) | 504 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) |
| 443 check(r, "sample_1mp.dng", SkISize::Make(600, 338), false, false, false); | 505 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); | 506 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 ); | 507 check(r, "dng_with_preview.dng", SkISize::Make(600, 338), true, false, false ); |
| 446 #endif | 508 #endif |
| 447 } | 509 } |
| 448 | 510 |
| 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) { | 511 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. | 512 // 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)); | 513 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals e)); |
| 543 REPORTER_ASSERT(r, !codec); | 514 REPORTER_ASSERT(r, !codec); |
| 544 | 515 |
| 545 SkAndroidCodec* androidCodec = | 516 SkAndroidCodec* androidCodec = |
| 546 SkAndroidCodec::NewFromStream(new SkMemoryStream(stream, len, false) ); | 517 SkAndroidCodec::NewFromStream(new SkMemoryStream(stream, len, false) ); |
| 547 REPORTER_ASSERT(r, !androidCodec); | 518 REPORTER_ASSERT(r, !androidCodec); |
| 548 } | 519 } |
| 549 | 520 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 672 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); | 643 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); |
| 673 } | 644 } |
| 674 | 645 |
| 675 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { | 646 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { |
| 676 SkAutoTDelete<SkStream> stream(resource(path)); | 647 SkAutoTDelete<SkStream> stream(resource(path)); |
| 677 if (!stream) { | 648 if (!stream) { |
| 678 SkDebugf("Missing resource '%s'\n", path); | 649 SkDebugf("Missing resource '%s'\n", path); |
| 679 return; | 650 return; |
| 680 } | 651 } |
| 681 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release())); | 652 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release())); |
| 653 if (!decoder) { | |
| 654 SkDebugf("Missing codec for %s\n", path); | |
| 655 return; | |
| 656 } | |
| 657 | |
| 658 const SkImageInfo info = decoder->getInfo().makeColorType(kIndex_8_SkColorTy pe); | |
| 682 | 659 |
| 683 // This should return kSuccess because kIndex8 is supported. | 660 // This should return kSuccess because kIndex8 is supported. |
| 684 SkPMColor colorStorage[256]; | 661 SkPMColor colorStorage[256]; |
| 685 int colorCount; | 662 int colorCount; |
| 686 SkCodec::Result result = decoder->startScanlineDecode( | 663 SkCodec::Result result = decoder->startScanlineDecode(info, nullptr, colorSt orage, |
| 687 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt orage, &colorCount); | 664 &colorCount); |
| 688 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 665 if (SkCodec::kSuccess == result) { |
| 689 // The rest of the test is uninteresting if kIndex8 is not supported | 666 // This should return kInvalidParameters because, in kIndex_8 mode, we m ust pass in a valid |
| 690 if (SkCodec::kSuccess != result) { | 667 // colorPtr and a valid colorCountPtr. |
| 668 result = decoder->startScanlineDecode(info, nullptr, nullptr, nullptr); | |
| 669 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | |
| 670 result = decoder->startScanlineDecode(info); | |
| 671 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | |
| 672 } else if (SkCodec::kUnimplemented == result) { | |
| 673 // New method should be supported: | |
| 674 SkBitmap bm; | |
| 675 sk_sp<SkColorTable> colorTable(new SkColorTable(colorStorage, 256)); | |
| 676 bm.allocPixels(info, nullptr, colorTable.get()); | |
| 677 result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowByt es(), nullptr, | |
| 678 colorStorage, &colorCount); | |
| 679 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | |
| 680 result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowByt es()); | |
| 681 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | |
| 682 } else { | |
| 683 // The test is uninteresting if kIndex8 is not supported | |
| 684 ERRORF(r, "Should not call test_invalid_parameters for non-Index8 file: %s\n", path); | |
| 691 return; | 685 return; |
| 692 } | 686 } |
| 693 | 687 |
| 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 } | 688 } |
| 703 | 689 |
| 704 DEF_TEST(Codec_Params, r) { | 690 DEF_TEST(Codec_Params, r) { |
| 705 test_invalid_parameters(r, "index8.png"); | 691 test_invalid_parameters(r, "index8.png"); |
| 706 test_invalid_parameters(r, "mandrill.wbmp"); | 692 test_invalid_parameters(r, "mandrill.wbmp"); |
| 707 } | 693 } |
| 708 | 694 |
| 709 static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { | 695 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); | 696 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); |
| 711 if (!sk_stream->write(data, len)) { | 697 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())); | 1157 codec.reset(SkCodec::NewFromStream(stream.release())); |
| 1172 | 1158 |
| 1173 for (SkAlphaType alphaType : alphaTypes) { | 1159 for (SkAlphaType alphaType : alphaTypes) { |
| 1174 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType) | 1160 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType) |
| 1175 .makeColorSpace(nullptr); | 1161 .makeColorSpace(nullptr); |
| 1176 check_round_trip(r, codec.get(), newInfo); | 1162 check_round_trip(r, codec.get(), newInfo); |
| 1177 } | 1163 } |
| 1178 } | 1164 } |
| 1179 | 1165 |
| 1180 static void test_conversion_possible(skiatest::Reporter* r, const char* path, | 1166 static void test_conversion_possible(skiatest::Reporter* r, const char* path, |
| 1181 bool testScanlineDecoder) { | 1167 bool supportsScanlineDecoder, |
| 1168 bool supportsIncrementalDecoder) { | |
| 1182 SkAutoTDelete<SkStream> stream(resource(path)); | 1169 SkAutoTDelete<SkStream> stream(resource(path)); |
| 1183 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); | 1170 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
| 1184 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); | 1171 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); |
| 1185 | 1172 |
| 1186 SkBitmap bm; | 1173 SkBitmap bm; |
| 1187 bm.allocPixels(infoF16); | 1174 bm.allocPixels(infoF16); |
| 1188 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt es()); | 1175 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt es()); |
| 1189 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | 1176 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
| 1190 if (testScanlineDecoder) { | 1177 |
| 1191 result = codec->startScanlineDecode(infoF16); | 1178 result = codec->startScanlineDecode(infoF16); |
| 1179 if (supportsScanlineDecoder) { | |
| 1192 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | 1180 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
| 1181 } else { | |
| 1182 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); | |
| 1183 } | |
| 1184 | |
| 1185 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes( )); | |
| 1186 if (supportsIncrementalDecoder) { | |
| 1187 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | |
| 1188 } else { | |
| 1189 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); | |
| 1193 } | 1190 } |
| 1194 | 1191 |
| 1195 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); | 1192 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); |
| 1196 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); | 1193 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); |
| 1197 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1194 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1198 if (testScanlineDecoder) { | 1195 result = codec->startScanlineDecode(infoF16); |
| 1199 result = codec->startScanlineDecode(infoF16); | 1196 if (supportsScanlineDecoder) { |
| 1200 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1197 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1198 } else { | |
| 1199 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); | |
| 1200 } | |
| 1201 | |
| 1202 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes( )); | |
| 1203 if (supportsIncrementalDecoder) { | |
| 1204 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | |
| 1205 } else { | |
| 1206 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result); | |
| 1201 } | 1207 } |
| 1202 } | 1208 } |
| 1203 | 1209 |
| 1204 DEF_TEST(Codec_F16ConversionPossible, r) { | 1210 DEF_TEST(Codec_F16ConversionPossible, r) { |
| 1205 test_conversion_possible(r, "color_wheel.webp", false); | 1211 test_conversion_possible(r, "color_wheel.webp", false, false); |
| 1206 test_conversion_possible(r, "mandrill_512_q075.jpg", true); | 1212 test_conversion_possible(r, "mandrill_512_q075.jpg", true, false); |
| 1207 test_conversion_possible(r, "yellow_rose.png", true); | 1213 test_conversion_possible(r, "yellow_rose.png", false, true); |
| 1208 } | 1214 } |
| 1215 | |
| 1216 // Only rewinds up to a limit. | |
| 1217 class LimitedRewindingStream : public SkStream { | |
| 1218 public: | |
| 1219 static SkStream* Make(const char path[], size_t limit) { | |
| 1220 SkStream* stream = resource(path); | |
| 1221 if (!stream) { | |
| 1222 return nullptr; | |
| 1223 } | |
| 1224 return new LimitedRewindingStream(stream, limit); | |
| 1225 } | |
| 1226 | |
| 1227 size_t read(void* buffer, size_t size) override { | |
| 1228 const size_t bytes = fStream->read(buffer, size); | |
| 1229 fPosition += bytes; | |
| 1230 return bytes; | |
| 1231 } | |
| 1232 | |
| 1233 bool isAtEnd() const override { | |
| 1234 return fStream->isAtEnd(); | |
| 1235 } | |
| 1236 | |
| 1237 bool rewind() override { | |
| 1238 if (fPosition <= fLimit && fStream->rewind()) { | |
| 1239 fPosition = 0; | |
| 1240 return true; | |
| 1241 } | |
| 1242 | |
| 1243 return false; | |
| 1244 } | |
| 1245 | |
| 1246 private: | |
| 1247 SkAutoTDelete<SkStream> fStream; | |
| 1248 const size_t fLimit; | |
| 1249 size_t fPosition; | |
| 1250 | |
| 1251 LimitedRewindingStream(SkStream* stream, size_t limit) | |
| 1252 : fStream(stream) | |
| 1253 , fLimit(limit) | |
| 1254 , fPosition(0) | |
| 1255 { | |
| 1256 SkASSERT(fStream); | |
| 1257 } | |
| 1258 }; | |
| 1259 | |
| 1260 DEF_TEST(Codec_fallBack, r) { | |
| 1261 // SkAndroidCodec needs to be able to fall back to scanline decoding | |
| 1262 // if incremental decoding does not work. Make sure this does not | |
| 1263 // require a rewind. | |
| 1264 | |
| 1265 // Formats that currently do not support incremental decoding | |
| 1266 auto files = { | |
| 1267 "box.gif", | |
| 1268 "CMYK.jpg", | |
| 1269 "color_wheel.ico", | |
| 1270 "mandrill.wbmp", | |
| 1271 "randPixels.bmp", | |
| 1272 }; | |
| 1273 for (auto file : files) { | |
| 1274 SkStream* stream = LimitedRewindingStream::Make(file, 14); | |
| 1275 if (!stream) { | |
| 1276 SkDebugf("Missing resources (%s). Set --resourcePath.\n", file); | |
| 1277 return; | |
| 1278 } | |
| 1279 | |
| 1280 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream)); | |
| 1281 if (!codec) { | |
| 1282 ERRORF(r, "Failed to create codec for %s,", file); | |
| 1283 continue; | |
| 1284 } | |
| 1285 | |
| 1286 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); | |
| 1287 SkBitmap bm; | |
| 1288 bm.allocPixels(info); | |
| 1289 | |
| 1290 if (SkCodec::kUnimplemented != codec->startIncrementalDecode(info, bm.ge tPixels(), | |
| 1291 bm.rowBytes())) { | |
| 1292 ERRORF(r, "Is scanline decoding now implemented for %s?", file); | |
| 1293 continue; | |
| 1294 } | |
| 1295 | |
| 1296 // Scanline decoding should not require a rewind. | |
| 1297 SkCodec::Result result = codec->startScanlineDecode(info); | |
| 1298 if (SkCodec::kSuccess != result) { | |
| 1299 ERRORF(r, "Scanline decoding failed for %s with %i", file, result); | |
| 1300 } | |
| 1301 } | |
| 1302 } | |
| OLD | NEW |