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); |
| 152 REPORTER_ASSERT(r, codec->skipScanlines(1) |
| 153 == SkCodec::kScanlineDecodingNotStarted); |
| 154 |
| 155 const SkCodec::Result startResult = codec->startScanlineDecode(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 |
| 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->startScanlineDecode(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 |
| 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 if (!codec) { |
| 285 return; |
| 286 } |
| 287 |
| 288 switch (codec->getScanlineOrder()) { |
| 289 case SkCodec::kBottomUp_SkScanlineOrder: |
| 290 case SkCodec::kOutOfOrder_SkScanlineOrder: |
| 291 ERRORF(r, "This scanline order will not match the original."); |
| 292 return; |
| 293 default: |
| 294 break; |
| 295 } |
| 296 |
| 297 // Baseline for what the image should look like, using N32. |
| 298 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
| 299 |
| 300 SkBitmap bm; |
| 301 bm.allocPixels(info); |
| 302 SkAutoLockPixels autoLockPixels(bm); |
| 303 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(
)); |
| 304 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 305 |
| 306 SkMD5::Digest digest; |
| 307 md5(bm, &digest); |
| 308 |
| 309 // Now decode in stripes |
| 310 const int height = info.height(); |
| 311 const int numStripes = 4; |
| 312 int stripeHeight; |
| 313 int remainingLines; |
| 314 SkTDivMod(height, numStripes, &stripeHeight, &remainingLines); |
| 315 |
| 316 bm.eraseColor(SK_ColorYELLOW); |
| 317 |
| 318 result = codec->startScanlineDecode(info); |
| 319 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 320 |
| 321 // Odd stripes |
| 322 for (int i = 1; i < numStripes; i += 2) { |
| 323 // Skip the even stripes |
| 324 result = codec->skipScanlines(stripeHeight); |
| 325 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 326 |
| 327 result = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeig
ht, |
| 328 bm.rowBytes()); |
| 329 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 330 } |
| 331 |
| 332 // Even stripes |
| 333 result = codec->startScanlineDecode(info); |
| 334 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 335 |
| 336 for (int i = 0; i < numStripes; i += 2) { |
| 337 result = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeig
ht, |
| 338 bm.rowBytes()); |
| 339 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 340 |
| 341 // Skip the odd stripes |
| 342 if (i + 1 < numStripes) { |
| 343 result = codec->skipScanlines(stripeHeight); |
| 344 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 345 } |
| 346 } |
| 347 |
| 348 // Remainder at the end |
| 349 if (remainingLines > 0) { |
| 350 result = codec->startScanlineDecode(info); |
| 351 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 352 |
| 353 result = codec->skipScanlines(height - remainingLines); |
| 354 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 355 |
| 356 result = codec->getScanlines(bm.getAddr(0, height - remainingLines), |
| 357 remainingLines, bm.rowBytes()); |
| 358 REPORTER_ASSERT(r, result == SkCodec::kSuccess); |
| 359 } |
| 360 |
| 361 compare_to_good_digest(r, digest, bm); |
| 362 } |
| 363 |
254 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_
t len) { | 364 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)); | 365 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. | 366 // We should not have gotten a codec. Bots should catch us if we leaked anyt
hing. |
257 REPORTER_ASSERT(r, !codec); | 367 REPORTER_ASSERT(r, !codec); |
258 } | 368 } |
259 | 369 |
260 // Ensure that SkCodec::NewFromStream handles freeing the passed in SkStream, | 370 // Ensure that SkCodec::NewFromStream handles freeing the passed in SkStream, |
261 // even on failure. Test some bad streams. | 371 // even on failure. Test some bad streams. |
262 DEF_TEST(Codec_leaks, r) { | 372 DEF_TEST(Codec_leaks, r) { |
263 // No codec should claim this as their format, so this tests SkCodec::NewFro
mStream. | 373 // 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. | 472 // This image is an ico with an embedded mask-bmp. This is illegal. |
363 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); | 473 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); |
364 } | 474 } |
365 | 475 |
366 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { | 476 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { |
367 SkAutoTDelete<SkStream> stream(resource(path)); | 477 SkAutoTDelete<SkStream> stream(resource(path)); |
368 if (!stream) { | 478 if (!stream) { |
369 SkDebugf("Missing resource '%s'\n", path); | 479 SkDebugf("Missing resource '%s'\n", path); |
370 return; | 480 return; |
371 } | 481 } |
372 SkAutoTDelete<SkScanlineDecoder> decoder(SkScanlineDecoder::NewFromStream( | 482 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.detach())); |
373 stream.detach())); | |
374 | 483 |
375 // This should return kSuccess because kIndex8 is supported. | 484 // This should return kSuccess because kIndex8 is supported. |
376 SkPMColor colorStorage[256]; | 485 SkPMColor colorStorage[256]; |
377 int colorCount; | 486 int colorCount; |
378 SkCodec::Result result = decoder->start( | 487 SkCodec::Result result = decoder->startScanlineDecode( |
379 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt
orage, &colorCount); | 488 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt
orage, &colorCount); |
380 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 489 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
381 // The rest of the test is uninteresting if kIndex8 is not supported | 490 // The rest of the test is uninteresting if kIndex8 is not supported |
382 if (SkCodec::kSuccess != result) { | 491 if (SkCodec::kSuccess != result) { |
383 return; | 492 return; |
384 } | 493 } |
385 | 494 |
386 // This should return kInvalidParameters because, in kIndex_8 mode, we must
pass in a valid | 495 // This should return kInvalidParameters because, in kIndex_8 mode, we must
pass in a valid |
387 // colorPtr and a valid colorCountPtr. | 496 // colorPtr and a valid colorCountPtr. |
388 result = decoder->start( | 497 result = decoder->startScanlineDecode( |
389 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, nullptr
, nullptr); | 498 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, nullptr
, nullptr); |
390 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 499 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
391 result = decoder->start( | 500 result = decoder->startScanlineDecode( |
392 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); | 501 decoder->getInfo().makeColorType(kIndex_8_SkColorType)); |
393 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); | 502 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result); |
394 } | 503 } |
395 | 504 |
396 DEF_TEST(Codec_Params, r) { | 505 DEF_TEST(Codec_Params, r) { |
397 test_invalid_parameters(r, "index8.png"); | 506 test_invalid_parameters(r, "index8.png"); |
398 test_invalid_parameters(r, "mandrill.wbmp"); | 507 test_invalid_parameters(r, "mandrill.wbmp"); |
399 } | 508 } |
OLD | NEW |