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 |