| 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" |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 rect.sort(); | 72 rect.sort(); |
| 73 } while (rect.isEmpty()); | 73 } while (rect.isEmpty()); |
| 74 return rect; | 74 return rect; |
| 75 } | 75 } |
| 76 | 76 |
| 77 static void check(skiatest::Reporter* r, | 77 static void check(skiatest::Reporter* r, |
| 78 const char path[], | 78 const char path[], |
| 79 SkISize size, | 79 SkISize size, |
| 80 bool supportsScanlineDecoding, | 80 bool supportsScanlineDecoding, |
| 81 bool supportsSubsetDecoding, | 81 bool supportsSubsetDecoding, |
| 82 bool supports565 = true) { | 82 bool supports565 = true, |
| 83 bool isIncomplete = false) { |
| 83 SkAutoTDelete<SkStream> stream(resource(path)); | 84 SkAutoTDelete<SkStream> stream(resource(path)); |
| 84 if (!stream) { | 85 if (!stream) { |
| 85 SkDebugf("Missing resource '%s'\n", path); | 86 SkDebugf("Missing resource '%s'\n", path); |
| 86 return; | 87 return; |
| 87 } | 88 } |
| 88 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach())); | 89 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach())); |
| 89 if (!codec) { | 90 if (!codec) { |
| 90 ERRORF(r, "Unable to decode '%s'", path); | 91 ERRORF(r, "Unable to decode '%s'", path); |
| 91 return; | 92 return; |
| 92 } | 93 } |
| 93 | 94 |
| 94 // This test is used primarily to verify rewinding works properly. Using kN
32 allows | 95 // This test is used primarily to verify rewinding works properly. Using kN
32 allows |
| 95 // us to test this without the added overhead of creating different bitmaps
depending | 96 // us to test this without the added overhead of creating different bitmaps
depending |
| 96 // on the color type (ex: building a color table for kIndex8). DM is where
we test | 97 // on the color type (ex: building a color table for kIndex8). DM is where
we test |
| 97 // decodes to all possible destination color types. | 98 // decodes to all possible destination color types. |
| 98 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); | 99 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
| 99 REPORTER_ASSERT(r, info.dimensions() == size); | 100 REPORTER_ASSERT(r, info.dimensions() == size); |
| 100 | 101 |
| 101 SkBitmap bm; | 102 SkBitmap bm; |
| 102 bm.allocPixels(info); | 103 bm.allocPixels(info); |
| 103 SkAutoLockPixels autoLockPixels(bm); | 104 SkAutoLockPixels autoLockPixels(bm); |
| 104 SkCodec::Result result = | 105 SkCodec::Result result = |
| 105 codec->getPixels(info, bm.getPixels(), bm.rowBytes(), nullptr, nullptr,
nullptr); | 106 codec->getPixels(info, bm.getPixels(), bm.rowBytes(), nullptr, nullptr,
nullptr); |
| 106 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 107 SkCodec::Result expected = isIncomplete ? SkCodec::kIncompleteInput : SkCode
c::kSuccess; |
| 108 REPORTER_ASSERT(r, result == expected); |
| 107 | 109 |
| 108 SkMD5::Digest digest; | 110 SkMD5::Digest digest; |
| 109 md5(bm, &digest); | 111 md5(bm, &digest); |
| 110 | 112 |
| 111 { | 113 { |
| 112 // Test decoding to 565 | 114 // Test decoding to 565 |
| 113 SkImageInfo info565 = info.makeColorType(kRGB_565_SkColorType); | 115 SkImageInfo info565 = info.makeColorType(kRGB_565_SkColorType); |
| 114 SkCodec::Result expected = (supports565 && info.alphaType() == kOpaque_S
kAlphaType) ? | 116 SkCodec::Result expected565 = (supports565 && info.alphaType() == kOpaqu
e_SkAlphaType) ? |
| 115 SkCodec::kSuccess : SkCodec::kInvalidConversion; | 117 SkCodec::kSuccess : SkCodec::kInvalidConversion; |
| 116 test_info(r, codec, info565, expected, nullptr); | 118 test_info(r, codec, info565, expected565, nullptr); |
| 117 } | 119 } |
| 118 | 120 |
| 119 // Verify that re-decoding gives the same result. It is interesting to chec
k this after | 121 // Verify that re-decoding gives the same result. It is interesting to chec
k this after |
| 120 // a decode to 565, since choosing to decode to 565 may result in some of th
e decode | 122 // a decode to 565, since choosing to decode to 565 may result in some of th
e decode |
| 121 // options being modified. These options should return to their defaults on
another | 123 // options being modified. These options should return to their defaults on
another |
| 122 // decode to kN32, so the new digest should match the old digest. | 124 // decode to kN32, so the new digest should match the old digest. |
| 123 test_info(r, codec, info, SkCodec::kSuccess, &digest); | 125 test_info(r, codec, info, expected, &digest); |
| 124 | 126 |
| 125 { | 127 { |
| 126 // Check alpha type conversions | 128 // Check alpha type conversions |
| 127 if (info.alphaType() == kOpaque_SkAlphaType) { | 129 if (info.alphaType() == kOpaque_SkAlphaType) { |
| 128 test_info(r, codec, info.makeAlphaType(kUnpremul_SkAlphaType), | 130 test_info(r, codec, info.makeAlphaType(kUnpremul_SkAlphaType), |
| 129 SkCodec::kInvalidConversion, nullptr); | 131 SkCodec::kInvalidConversion, nullptr); |
| 130 test_info(r, codec, info.makeAlphaType(kPremul_SkAlphaType), | 132 test_info(r, codec, info.makeAlphaType(kPremul_SkAlphaType), |
| 131 SkCodec::kInvalidConversion, nullptr); | 133 SkCodec::kInvalidConversion, nullptr); |
| 132 } else { | 134 } else { |
| 133 // Decoding to opaque should fail | 135 // Decoding to opaque should fail |
| 134 test_info(r, codec, info.makeAlphaType(kOpaque_SkAlphaType), | 136 test_info(r, codec, info.makeAlphaType(kOpaque_SkAlphaType), |
| 135 SkCodec::kInvalidConversion, nullptr); | 137 SkCodec::kInvalidConversion, nullptr); |
| 136 SkAlphaType otherAt = info.alphaType(); | 138 SkAlphaType otherAt = info.alphaType(); |
| 137 if (kPremul_SkAlphaType == otherAt) { | 139 if (kPremul_SkAlphaType == otherAt) { |
| 138 otherAt = kUnpremul_SkAlphaType; | 140 otherAt = kUnpremul_SkAlphaType; |
| 139 } else { | 141 } else { |
| 140 otherAt = kPremul_SkAlphaType; | 142 otherAt = kPremul_SkAlphaType; |
| 141 } | 143 } |
| 142 // The other non-opaque alpha type should always succeed, but not ma
tch. | 144 // The other non-opaque alpha type should always succeed, but not ma
tch. |
| 143 test_info(r, codec, info.makeAlphaType(otherAt), SkCodec::kSuccess,
nullptr); | 145 test_info(r, codec, info.makeAlphaType(otherAt), expected, nullptr); |
| 144 } | 146 } |
| 145 } | 147 } |
| 146 | 148 |
| 147 // Scanline decoding follows. | 149 // Scanline decoding follows. |
| 148 | 150 |
| 149 // Need to call start() first. | 151 // Need to call startScanlineDecode() first. |
| 150 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 152 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) == 0); |
| 151 == SkCodec::kScanlineDecodingNotStarted); | 153 REPORTER_ASSERT(r, codec->skipScanlines(1) == 0); |
| 152 REPORTER_ASSERT(r, codec->skipScanlines(1) | |
| 153 == SkCodec::kScanlineDecodingNotStarted); | |
| 154 | 154 |
| 155 const SkCodec::Result startResult = codec->startScanlineDecode(info); | 155 const SkCodec::Result startResult = codec->startScanlineDecode(info); |
| 156 if (supportsScanlineDecoding) { | 156 if (supportsScanlineDecoding) { |
| 157 bm.eraseColor(SK_ColorYELLOW); | 157 bm.eraseColor(SK_ColorYELLOW); |
| 158 | 158 |
| 159 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess); | 159 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess); |
| 160 | 160 |
| 161 for (int y = 0; y < info.height(); y++) { | 161 for (int y = 0; y < info.height(); y++) { |
| 162 result = codec->getScanlines(bm.getAddr(0, y), 1, 0); | 162 const uint32_t lines = codec->getScanlines(bm.getAddr(0, y), 1, 0); |
| 163 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 163 if (!isIncomplete) { |
| 164 REPORTER_ASSERT(r, 1 == lines); |
| 165 } |
| 164 } | 166 } |
| 165 // verify that scanline decoding gives the same result. | 167 // verify that scanline decoding gives the same result. |
| 166 if (SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()) { | 168 if (SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()) { |
| 167 compare_to_good_digest(r, digest, bm); | 169 compare_to_good_digest(r, digest, bm); |
| 168 } | 170 } |
| 169 | 171 |
| 170 // Cannot continue to decode scanlines beyond the end | 172 // Cannot continue to decode scanlines beyond the end |
| 171 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 173 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
| 172 == SkCodec::kInvalidParameters); | 174 == 0); |
| 173 | 175 |
| 174 // Interrupting a scanline decode with a full decode starts from | 176 // Interrupting a scanline decode with a full decode starts from |
| 175 // scratch | 177 // scratch |
| 176 REPORTER_ASSERT(r, codec->startScanlineDecode(info) == SkCodec::kSuccess
); | 178 REPORTER_ASSERT(r, codec->startScanlineDecode(info) == SkCodec::kSuccess
); |
| 177 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 179 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
| 178 == SkCodec::kSuccess); | 180 == 1); |
| 179 REPORTER_ASSERT(r, codec->getPixels(bm.info(), bm.getPixels(), bm.rowByt
es()) | 181 REPORTER_ASSERT(r, codec->getPixels(bm.info(), bm.getPixels(), bm.rowByt
es()) |
| 180 == SkCodec::kSuccess); | 182 == expected); |
| 181 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) | 183 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) |
| 182 == SkCodec::kScanlineDecodingNotStarted); | 184 == 0); |
| 183 REPORTER_ASSERT(r, codec->skipScanlines(1) | 185 REPORTER_ASSERT(r, codec->skipScanlines(1) |
| 184 == SkCodec::kScanlineDecodingNotStarted); | 186 == 0); |
| 185 } else { | 187 } else { |
| 186 REPORTER_ASSERT(r, startResult == SkCodec::kUnimplemented); | 188 REPORTER_ASSERT(r, startResult == SkCodec::kUnimplemented); |
| 187 } | 189 } |
| 188 | 190 |
| 189 // The rest of this function tests decoding subsets, and will decode an arbi
trary number of | 191 // The rest of this function tests decoding subsets, and will decode an arbi
trary number of |
| 190 // random subsets. | 192 // random subsets. |
| 191 // Do not attempt to decode subsets of an image of only once pixel, since th
ere is no | 193 // Do not attempt to decode subsets of an image of only once pixel, since th
ere is no |
| 192 // meaningful subset. | 194 // meaningful subset. |
| 193 if (size.width() * size.height() == 1) { | 195 if (size.width() * size.height() == 1) { |
| 194 return; | 196 return; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false); | 263 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false); |
| 262 check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false); | 264 check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false); |
| 263 check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false); | 265 check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false); |
| 264 check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false); | 266 check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false); |
| 265 check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false); | 267 check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false); |
| 266 check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false); | 268 check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false); |
| 267 check(r, "plane.png", SkISize::Make(250, 126), true, false); | 269 check(r, "plane.png", SkISize::Make(250, 126), true, false); |
| 268 check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false); | 270 check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false); |
| 269 check(r, "randPixels.png", SkISize::Make(8, 8), true, false); | 271 check(r, "randPixels.png", SkISize::Make(8, 8), true, false); |
| 270 check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false); | 272 check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false); |
| 273 // Incomplete Image |
| 274 check(r, "incomplete_images/android.png", SkISize::Make(1024, 1218), true, f
alse, true, true); |
| 271 } | 275 } |
| 272 | 276 |
| 273 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode | 277 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode |
| 274 DEF_TEST(Codec_stripes, r) { | 278 DEF_TEST(Codec_stripes, r) { |
| 275 const char * path = "plane_interlaced.png"; | 279 const char * path = "plane_interlaced.png"; |
| 276 SkAutoTDelete<SkStream> stream(resource(path)); | 280 SkAutoTDelete<SkStream> stream(resource(path)); |
| 277 if (!stream) { | 281 if (!stream) { |
| 278 SkDebugf("Missing resource '%s'\n", path); | 282 SkDebugf("Missing resource '%s'\n", path); |
| 279 } | 283 } |
| 280 | 284 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 SkTDivMod(height, numStripes, &stripeHeight, &remainingLines); | 318 SkTDivMod(height, numStripes, &stripeHeight, &remainingLines); |
| 315 | 319 |
| 316 bm.eraseColor(SK_ColorYELLOW); | 320 bm.eraseColor(SK_ColorYELLOW); |
| 317 | 321 |
| 318 result = codec->startScanlineDecode(info); | 322 result = codec->startScanlineDecode(info); |
| 319 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 323 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 320 | 324 |
| 321 // Odd stripes | 325 // Odd stripes |
| 322 for (int i = 1; i < numStripes; i += 2) { | 326 for (int i = 1; i < numStripes; i += 2) { |
| 323 // Skip the even stripes | 327 // Skip the even stripes |
| 324 result = codec->skipScanlines(stripeHeight); | 328 bool skipResult = codec->skipScanlines(stripeHeight); |
| 325 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 329 REPORTER_ASSERT(r, skipResult); |
| 326 | 330 |
| 327 result = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeig
ht, | 331 int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight),
stripeHeight, |
| 328 bm.rowBytes()); | 332 bm.rowBytes()); |
| 329 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 333 REPORTER_ASSERT(r, linesDecoded == stripeHeight); |
| 330 } | 334 } |
| 331 | 335 |
| 332 // Even stripes | 336 // Even stripes |
| 333 result = codec->startScanlineDecode(info); | 337 result = codec->startScanlineDecode(info); |
| 334 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 338 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 335 | 339 |
| 336 for (int i = 0; i < numStripes; i += 2) { | 340 for (int i = 0; i < numStripes; i += 2) { |
| 337 result = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeig
ht, | 341 int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight),
stripeHeight, |
| 338 bm.rowBytes()); | 342 bm.rowBytes()); |
| 339 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 343 REPORTER_ASSERT(r, linesDecoded == stripeHeight); |
| 340 | 344 |
| 341 // Skip the odd stripes | 345 // Skip the odd stripes |
| 342 if (i + 1 < numStripes) { | 346 if (i + 1 < numStripes) { |
| 343 result = codec->skipScanlines(stripeHeight); | 347 bool skipResult = codec->skipScanlines(stripeHeight); |
| 344 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 348 REPORTER_ASSERT(r, skipResult); |
| 345 } | 349 } |
| 346 } | 350 } |
| 347 | 351 |
| 348 // Remainder at the end | 352 // Remainder at the end |
| 349 if (remainingLines > 0) { | 353 if (remainingLines > 0) { |
| 350 result = codec->startScanlineDecode(info); | 354 result = codec->startScanlineDecode(info); |
| 351 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 355 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 352 | 356 |
| 353 result = codec->skipScanlines(height - remainingLines); | 357 bool skipResult = codec->skipScanlines(height - remainingLines); |
| 354 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 358 REPORTER_ASSERT(r, skipResult); |
| 355 | 359 |
| 356 result = codec->getScanlines(bm.getAddr(0, height - remainingLines), | 360 int linesDecoded = codec->getScanlines(bm.getAddr(0, height - remainingL
ines), |
| 357 remainingLines, bm.rowBytes()); | 361 remainingLines, bm.rowBytes()); |
| 358 REPORTER_ASSERT(r, result == SkCodec::kSuccess); | 362 REPORTER_ASSERT(r, linesDecoded == remainingLines); |
| 359 } | 363 } |
| 360 | 364 |
| 361 compare_to_good_digest(r, digest, bm); | 365 compare_to_good_digest(r, digest, bm); |
| 362 } | 366 } |
| 363 | 367 |
| 364 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_
t len) { | 368 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_
t len) { |
| 365 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals
e)); | 369 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals
e)); |
| 366 // We should not have gotten a codec. Bots should catch us if we leaked anyt
hing. | 370 // We should not have gotten a codec. Bots should catch us if we leaked anyt
hing. |
| 367 REPORTER_ASSERT(r, !codec); | 371 REPORTER_ASSERT(r, !codec); |
| 368 } | 372 } |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 503 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 500 result = decoder->startScanlineDecode( | 504 result = decoder->startScanlineDecode( |
| 501 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); | 505 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); |
| 502 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 506 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
| 503 } | 507 } |
| 504 | 508 |
| 505 DEF_TEST(Codec_Params, r) { | 509 DEF_TEST(Codec_Params, r) { |
| 506 test_invalid_parameters(r, "index8.png"); | 510 test_invalid_parameters(r, "index8.png"); |
| 507 test_invalid_parameters(r, "mandrill.wbmp"); | 511 test_invalid_parameters(r, "mandrill.wbmp"); |
| 508 } | 512 } |
| OLD | NEW |