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 |