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 "SkBitmap.h" | 9 #include "SkBitmap.h" |
| 10 #include "SkCodec.h" | 10 #include "SkCodec.h" |
| 11 #include "SkMD5.h" | 11 #include "SkMD5.h" |
| 12 #include "SkRandom.h" | 12 #include "SkRandom.h" |
| 13 #include "SkScaledCodec.h" | 13 #include "SkScaledCodec.h" |
| 14 #include "SkScanlineDecoder.h" | |
| 15 #include "Test.h" | 14 #include "Test.h" |
| 16 | 15 |
| 17 static SkStreamAsset* resource(const char path[]) { | 16 static SkStreamAsset* resource(const char path[]) { |
| 18 SkString fullPath = GetResourcePath(path); | 17 SkString fullPath = GetResourcePath(path); |
| 19 return SkStream::NewFromFile(fullPath.c_str()); | 18 return SkStream::NewFromFile(fullPath.c_str()); |
| 20 } | 19 } |
| 21 | 20 |
| 22 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) { | 21 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) { |
| 23 SkAutoLockPixels autoLockPixels(bm); | 22 SkAutoLockPixels autoLockPixels(bm); |
| 24 SkASSERT(bm.getPixels()); | 23 SkASSERT(bm.getPixels()); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 } else { | 139 } else { |
| 141 otherAt = kPremul_SkAlphaType; | 140 otherAt = kPremul_SkAlphaType; |
| 142 } | 141 } |
| 143 // The other non-opaque alpha type should always succeed, but not ma tch. | 142 // The other non-opaque alpha type should always succeed, but not ma tch. |
| 144 test_info(r, codec, info.makeAlphaType(otherAt), SkCodec::kSuccess, nullptr); | 143 test_info(r, codec, info.makeAlphaType(otherAt), SkCodec::kSuccess, nullptr); |
| 145 } | 144 } |
| 146 } | 145 } |
| 147 | 146 |
| 148 // Scanline decoding follows. | 147 // Scanline decoding follows. |
| 149 | 148 |
| 150 stream.reset(resource(path)); | 149 // Need to call start() first. |
| 151 SkAutoTDelete<SkScanlineDecoder> scanlineDecoder( | 150 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
| 152 SkScanlineDecoder::NewFromStream(stream.detach())); | 151 == SkCodec::kScanlineDecodingNotStarted); |
|
scroggo
2015/09/25 16:07:50
Again, these can check for 0/false once we change
| |
| 152 REPORTER_ASSERT(r, codec->skipScanlines(1) | |
| 153 == SkCodec::kScanlineDecodingNotStarted); | |
| 154 | |
| 155 const SkCodec::Result startResult = codec->start(info); | |
| 153 if (supportsScanlineDecoding) { | 156 if (supportsScanlineDecoding) { |
| 154 bm.eraseColor(SK_ColorYELLOW); | 157 bm.eraseColor(SK_ColorYELLOW); |
| 155 REPORTER_ASSERT(r, scanlineDecoder); | |
| 156 | 158 |
| 157 REPORTER_ASSERT(r, scanlineDecoder->start(info) == SkCodec::kSuccess); | 159 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess); |
| 158 | 160 |
| 159 for (int y = 0; y < info.height(); y++) { | 161 for (int y = 0; y < info.height(); y++) { |
| 160 result = scanlineDecoder->getScanlines(bm.getAddr(0, y), 1, 0); | 162 result = codec->getScanlines(bm.getAddr(0, y), 1, 0); |
| 161 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 163 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 162 } | 164 } |
| 163 // verify that scanline decoding gives the same result. | 165 // verify that scanline decoding gives the same result. |
| 164 if (SkScanlineDecoder::kTopDown_SkScanlineOrder == scanlineDecoder->getS canlineOrder()) { | 166 if (SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()) { |
| 165 compare_to_good_digest(r, digest, bm); | 167 compare_to_good_digest(r, digest, bm); |
| 166 } | 168 } |
| 169 | |
| 170 // Cannot continue to decode scanlines beyond the end | |
|
msarett
2015/09/28 14:48:50
+1 for new tests
| |
| 171 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | |
| 172 == SkCodec::kInvalidParameters); | |
| 173 | |
| 174 // Interrupting a scanline decode with a full decode starts from | |
| 175 // scratch | |
| 176 REPORTER_ASSERT(r, codec->start(info) == SkCodec::kSuccess); | |
| 177 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | |
| 178 == SkCodec::kSuccess); | |
| 179 REPORTER_ASSERT(r, codec->getPixels(bm.info(), bm.getPixels(), bm.rowByt es()) | |
| 180 == SkCodec::kSuccess); | |
| 181 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | |
| 182 == SkCodec::kScanlineDecodingNotStarted); | |
| 183 REPORTER_ASSERT(r, codec->skipScanlines(1) | |
| 184 == SkCodec::kScanlineDecodingNotStarted); | |
| 167 } else { | 185 } else { |
| 168 REPORTER_ASSERT(r, !scanlineDecoder); | 186 REPORTER_ASSERT(r, startResult == SkCodec::kUnimplemented); |
| 169 } | 187 } |
| 170 | 188 |
| 171 // The rest of this function tests decoding subsets, and will decode an arbi trary number of | 189 // The rest of this function tests decoding subsets, and will decode an arbi trary number of |
| 172 // random subsets. | 190 // random subsets. |
| 173 // Do not attempt to decode subsets of an image of only once pixel, since th ere is no | 191 // Do not attempt to decode subsets of an image of only once pixel, since th ere is no |
| 174 // meaningful subset. | 192 // meaningful subset. |
| 175 if (size.width() * size.height() == 1) { | 193 if (size.width() * size.height() == 1) { |
| 176 return; | 194 return; |
| 177 } | 195 } |
| 178 | 196 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 check(r, "baby_tux.png", SkISize::Make(240, 246), true, false); | 258 check(r, "baby_tux.png", SkISize::Make(240, 246), true, false); |
| 241 check(r, "color_wheel.png", SkISize::Make(128, 128), true, false); | 259 check(r, "color_wheel.png", SkISize::Make(128, 128), true, false); |
| 242 check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), true, fals e); | 260 check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), true, fals e); |
| 243 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false); | 261 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false); |
| 244 check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false); | 262 check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false); |
| 245 check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false); | 263 check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false); |
| 246 check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false); | 264 check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false); |
| 247 check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false); | 265 check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false); |
| 248 check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false); | 266 check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false); |
| 249 check(r, "plane.png", SkISize::Make(250, 126), true, false); | 267 check(r, "plane.png", SkISize::Make(250, 126), true, false); |
| 268 check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false); | |
| 250 check(r, "randPixels.png", SkISize::Make(8, 8), true, false); | 269 check(r, "randPixels.png", SkISize::Make(8, 8), true, false); |
| 251 check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false); | 270 check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false); |
| 252 } | 271 } |
| 253 | 272 |
| 273 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode | |
|
scroggo
2015/09/25 16:07:50
Maybe this test is redundant with kStripe_Mode, bu
msarett
2015/09/28 14:48:50
I like this as a separate test - I think it's good
scroggo
2015/09/28 16:01:53
Thanks for the feedback. FWIW, I don't think anyth
| |
| 274 DEF_TEST(Codec_stripes, r) { | |
| 275 const char * path = "plane_interlaced.png"; | |
| 276 SkAutoTDelete<SkStream> stream(resource(path)); | |
| 277 if (!stream) { | |
| 278 SkDebugf("Missing resource '%s'\n", path); | |
| 279 } | |
| 280 | |
| 281 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach())); | |
| 282 REPORTER_ASSERT(r, codec); | |
| 283 | |
| 284 // Baseline for what the image should look like, using N32. | |
| 285 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); | |
| 286 | |
| 287 SkBitmap bm; | |
| 288 bm.allocPixels(info); | |
| 289 SkAutoLockPixels autoLockPixels(bm); | |
| 290 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes( )); | |
| 291 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 292 | |
| 293 SkMD5::Digest digest; | |
| 294 md5(bm, &digest); | |
| 295 | |
| 296 // Now decode in stripes | |
| 297 const int height = info.height(); | |
| 298 const int numStripes = 4; | |
| 299 int stripeHeight; | |
| 300 int remainingLines; | |
| 301 SkTDivMod(height, numStripes, &stripeHeight, &remainingLines); | |
| 302 | |
| 303 bm.eraseColor(SK_ColorYELLOW); | |
| 304 | |
| 305 result = codec->start(info); | |
| 306 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 307 | |
| 308 // Odd stripes | |
| 309 for (int i = 1; i < numStripes; i += 2) { | |
| 310 // Skip the even stripes | |
| 311 result = codec->skipScanlines(stripeHeight); | |
| 312 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 313 | |
| 314 result = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeig ht, | |
| 315 bm.rowBytes()); | |
| 316 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 317 } | |
| 318 | |
| 319 // Even stripes | |
| 320 result = codec->start(info); | |
| 321 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 322 | |
| 323 for (int i = 0; i < numStripes; i += 2) { | |
| 324 result = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeig ht, | |
| 325 bm.rowBytes()); | |
| 326 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 327 | |
| 328 // Skip the odd stripes | |
| 329 if (i + 1 < numStripes) { | |
| 330 result = codec->skipScanlines(stripeHeight); | |
| 331 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 // Remainder at the end | |
| 336 if (remainingLines > 0) { | |
| 337 result = codec->start(info); | |
| 338 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 339 | |
| 340 result = codec->skipScanlines(height - remainingLines); | |
| 341 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 342 | |
| 343 result = codec->getScanlines(bm.getAddr(0, height - remainingLines), | |
| 344 remainingLines, bm.rowBytes()); | |
| 345 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | |
| 346 } | |
| 347 | |
| 348 compare_to_good_digest(r, digest, bm); | |
| 349 } | |
| 350 | |
| 254 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_ t len) { | 351 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_ t len) { |
| 255 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals e)); | 352 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals e)); |
| 256 // We should not have gotten a codec. Bots should catch us if we leaked anyt hing. | 353 // We should not have gotten a codec. Bots should catch us if we leaked anyt hing. |
| 257 REPORTER_ASSERT(r, !codec); | 354 REPORTER_ASSERT(r, !codec); |
| 258 } | 355 } |
| 259 | 356 |
| 260 // Ensure that SkCodec::NewFromStream handles freeing the passed in SkStream, | 357 // Ensure that SkCodec::NewFromStream handles freeing the passed in SkStream, |
| 261 // even on failure. Test some bad streams. | 358 // even on failure. Test some bad streams. |
| 262 DEF_TEST(Codec_leaks, r) { | 359 DEF_TEST(Codec_leaks, r) { |
| 263 // No codec should claim this as their format, so this tests SkCodec::NewFro mStream. | 360 // No codec should claim this as their format, so this tests SkCodec::NewFro mStream. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 362 // This image is an ico with an embedded mask-bmp. This is illegal. | 459 // This image is an ico with an embedded mask-bmp. This is illegal. |
| 363 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); | 460 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); |
| 364 } | 461 } |
| 365 | 462 |
| 366 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { | 463 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { |
| 367 SkAutoTDelete<SkStream> stream(resource(path)); | 464 SkAutoTDelete<SkStream> stream(resource(path)); |
| 368 if (!stream) { | 465 if (!stream) { |
| 369 SkDebugf("Missing resource '%s'\n", path); | 466 SkDebugf("Missing resource '%s'\n", path); |
| 370 return; | 467 return; |
| 371 } | 468 } |
| 372 SkAutoTDelete<SkScanlineDecoder> decoder(SkScanlineDecoder::NewFromStream( | 469 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.detach())); |
| 373 stream.detach())); | |
| 374 | 470 |
| 375 // This should return kSuccess because kIndex8 is supported. | 471 // This should return kSuccess because kIndex8 is supported. |
| 376 SkPMColor colorStorage[256]; | 472 SkPMColor colorStorage[256]; |
| 377 int colorCount; | 473 int colorCount; |
| 378 SkCodec::Result result = decoder->start( | 474 SkCodec::Result result = decoder->start( |
| 379 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt orage, &colorCount); | 475 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt orage, &colorCount); |
| 380 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 476 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 381 // The rest of the test is uninteresting if kIndex8 is not supported | 477 // The rest of the test is uninteresting if kIndex8 is not supported |
| 382 if (SkCodec::kSuccess != result) { | 478 if (SkCodec::kSuccess != result) { |
| 383 return; | 479 return; |
| 384 } | 480 } |
| 385 | 481 |
| 386 // This should return kInvalidParameters because, in kIndex_8 mode, we must pass in a valid | 482 // This should return kInvalidParameters because, in kIndex_8 mode, we must pass in a valid |
| 387 // colorPtr and a valid colorCountPtr. | 483 // colorPtr and a valid colorCountPtr. |
| 388 result = decoder->start( | 484 result = decoder->start( |
| 389 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, nullptr , nullptr); | 485 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, nullptr , nullptr); |
| 390 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 486 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 391 result = decoder->start( | 487 result = decoder->start( |
| 392 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); | 488 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); |
| 393 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 489 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 394 } | 490 } |
| 395 | 491 |
| 396 DEF_TEST(Codec_Params, r) { | 492 DEF_TEST(Codec_Params, r) { |
| 397 test_invalid_parameters(r, "index8.png"); | 493 test_invalid_parameters(r, "index8.png"); |
| 398 test_invalid_parameters(r, "mandrill.wbmp"); | 494 test_invalid_parameters(r, "mandrill.wbmp"); |
| 399 } | 495 } |
| OLD | NEW |