blob: e07432ae25687d8e79de164b1e3d8e23fed5523d [file] [log] [blame]
scroggo8e6c7ad2016-09-16 08:20:38 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -05008#include "CodecPriv.h"
Ben Wagnerb607a8f2018-03-12 13:46:21 -04009#include "FakeStreams.h"
10#include "Resources.h"
scroggo8e6c7ad2016-09-16 08:20:38 -070011#include "SkBitmap.h"
12#include "SkCodec.h"
13#include "SkData.h"
14#include "SkImageInfo.h"
Mike Reedede7bac2017-07-23 15:30:02 -040015#include "SkMakeUnique.h"
Ben Wagnerb607a8f2018-03-12 13:46:21 -040016#include "SkRefCnt.h"
17#include "SkStream.h"
18#include "SkTypes.h"
Ben Wagner501c17c2018-03-12 20:04:31 +000019#include "Test.h"
Ben Wagner1a462bd2018-03-12 13:46:21 -040020
Ben Wagnerb607a8f2018-03-12 13:46:21 -040021#include <cstring>
22#include <memory>
23#include <utility>
24#include <vector>
25
scroggo8e6c7ad2016-09-16 08:20:38 -070026static SkImageInfo standardize_info(SkCodec* codec) {
27 SkImageInfo defaultInfo = codec->getInfo();
28 // Note: This drops the SkColorSpace, allowing the equality check between two
29 // different codecs created from the same file to have the same SkImageInfo.
30 return SkImageInfo::MakeN32Premul(defaultInfo.width(), defaultInfo.height());
31}
32
33static bool create_truth(sk_sp<SkData> data, SkBitmap* dst) {
Mike Reedede7bac2017-07-23 15:30:02 -040034 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(std::move(data)));
scroggo8e6c7ad2016-09-16 08:20:38 -070035 if (!codec) {
36 return false;
37 }
38
Ben Wagner145dbcd2016-11-03 14:40:50 -040039 const SkImageInfo info = standardize_info(codec.get());
scroggo8e6c7ad2016-09-16 08:20:38 -070040 dst->allocPixels(info);
41 return SkCodec::kSuccess == codec->getPixels(info, dst->getPixels(), dst->rowBytes());
42}
43
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -050044static bool compare_bitmaps(skiatest::Reporter* r, const SkBitmap& bm1, const SkBitmap& bm2) {
scroggo19b91532016-10-24 09:03:26 -070045 const SkImageInfo& info = bm1.info();
46 if (info != bm2.info()) {
47 ERRORF(r, "Bitmaps have different image infos!");
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -050048 return false;
scroggo19b91532016-10-24 09:03:26 -070049 }
50 const size_t rowBytes = info.minRowBytes();
51 for (int i = 0; i < info.height(); i++) {
nagarajan.n0ec0bf02017-10-11 10:41:27 +053052 if (memcmp(bm1.getAddr(0, i), bm2.getAddr(0, i), rowBytes)) {
53 ERRORF(r, "Bitmaps have different pixels, starting on line %i!", i);
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -050054 return false;
nagarajan.n0ec0bf02017-10-11 10:41:27 +053055 }
scroggo19b91532016-10-24 09:03:26 -070056 }
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -050057
58 return true;
scroggo19b91532016-10-24 09:03:26 -070059}
60
Leon Scroggins III4993b952016-12-08 11:54:04 -050061static void test_partial(skiatest::Reporter* r, const char* name, size_t minBytes = 0) {
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -050062 sk_sp<SkData> file = GetResourceAsData(name);
scroggo8e6c7ad2016-09-16 08:20:38 -070063 if (!file) {
64 SkDebugf("missing resource %s\n", name);
65 return;
66 }
67
68 SkBitmap truth;
69 if (!create_truth(file, &truth)) {
70 ERRORF(r, "Failed to decode %s\n", name);
71 return;
72 }
73
scroggo8e6c7ad2016-09-16 08:20:38 -070074 // Now decode part of the file
Leon Scroggins III4993b952016-12-08 11:54:04 -050075 HaltingStream* stream = new HaltingStream(file, SkTMax(file->size() / 2, minBytes));
scroggo8e6c7ad2016-09-16 08:20:38 -070076
77 // Note that we cheat and hold on to a pointer to stream, though it is owned by
78 // partialCodec.
Mike Reedede7bac2017-07-23 15:30:02 -040079 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream)));
scroggo8e6c7ad2016-09-16 08:20:38 -070080 if (!partialCodec) {
81 // Technically, this could be a small file where half the file is not
82 // enough.
83 ERRORF(r, "Failed to create codec for %s", name);
84 return;
85 }
86
Ben Wagner145dbcd2016-11-03 14:40:50 -040087 const SkImageInfo info = standardize_info(partialCodec.get());
scroggo8e6c7ad2016-09-16 08:20:38 -070088 SkASSERT(info == truth.info());
89 SkBitmap incremental;
90 incremental.allocPixels(info);
91
scroggo19b91532016-10-24 09:03:26 -070092 while (true) {
93 const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info,
94 incremental.getPixels(), incremental.rowBytes());
95 if (startResult == SkCodec::kSuccess) {
96 break;
97 }
98
99 if (stream->isAllDataReceived()) {
100 ERRORF(r, "Failed to start incremental decode\n");
101 return;
102 }
103
104 // Append some data. The size is arbitrary, but deliberately different from
105 // the buffer size used by SkPngCodec.
106 stream->addNewData(1000);
scroggo8e6c7ad2016-09-16 08:20:38 -0700107 }
108
109 while (true) {
110 const SkCodec::Result result = partialCodec->incrementalDecode();
111
scroggo19b91532016-10-24 09:03:26 -0700112 if (result == SkCodec::kSuccess) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700113 break;
114 }
115
scroggo8e6c7ad2016-09-16 08:20:38 -0700116 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
117
scroggo19b91532016-10-24 09:03:26 -0700118 if (stream->isAllDataReceived()) {
119 ERRORF(r, "Failed to completely decode %s", name);
120 return;
121 }
122
123 // Append some data. The size is arbitrary, but deliberately different from
124 // the buffer size used by SkPngCodec.
125 stream->addNewData(1000);
scroggo8e6c7ad2016-09-16 08:20:38 -0700126 }
127
128 // compare to original
scroggo19b91532016-10-24 09:03:26 -0700129 compare_bitmaps(r, truth, incremental);
scroggo8e6c7ad2016-09-16 08:20:38 -0700130}
131
132DEF_TEST(Codec_partial, r) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400133#if 0
134 // FIXME (scroggo): SkPngCodec needs to use SkStreamBuffer in order to
135 // support incremental decoding.
Hal Canaryc465d132017-12-08 10:21:31 -0500136 test_partial(r, "images/plane.png");
137 test_partial(r, "images/plane_interlaced.png");
138 test_partial(r, "images/yellow_rose.png");
139 test_partial(r, "images/index8.png");
140 test_partial(r, "images/color_wheel.png");
141 test_partial(r, "images/mandrill_256.png");
142 test_partial(r, "images/mandrill_32.png");
143 test_partial(r, "images/arrow.png");
144 test_partial(r, "images/randPixels.png");
145 test_partial(r, "images/baby_tux.png");
Leon Scroggins III83239652017-04-21 13:47:12 -0400146#endif
Hal Canaryc465d132017-12-08 10:21:31 -0500147 test_partial(r, "images/box.gif");
148 test_partial(r, "images/randPixels.gif", 215);
149 test_partial(r, "images/color_wheel.gif");
scroggo19b91532016-10-24 09:03:26 -0700150}
151
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500152// Verify that when decoding an animated gif byte by byte we report the correct
153// fRequiredFrame as soon as getFrameInfo reports the frame.
154DEF_TEST(Codec_requiredFrame, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500155 auto path = "images/colorTables.gif";
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500156 sk_sp<SkData> file = GetResourceAsData(path);
157 if (!file) {
158 return;
159 }
160
Mike Reedede7bac2017-07-23 15:30:02 -0400161 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(file));
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500162 if (!codec) {
163 ERRORF(r, "Failed to create codec from %s", path);
164 return;
165 }
166
167 auto frameInfo = codec->getFrameInfo();
168 if (frameInfo.size() <= 1) {
169 ERRORF(r, "Test is uninteresting with 0 or 1 frames");
170 return;
171 }
172
173 HaltingStream* stream(nullptr);
174 std::unique_ptr<SkCodec> partialCodec(nullptr);
175 for (size_t i = 0; !partialCodec; i++) {
176 if (file->size() == i) {
177 ERRORF(r, "Should have created a partial codec for %s", path);
178 return;
179 }
180 stream = new HaltingStream(file, i);
Mike Reedede7bac2017-07-23 15:30:02 -0400181 partialCodec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500182 }
183
184 std::vector<SkCodec::FrameInfo> partialInfo;
185 size_t frameToCompare = 0;
Nigel Taoafea9c32018-08-01 15:00:32 +1000186 while (true) {
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500187 partialInfo = partialCodec->getFrameInfo();
188 for (; frameToCompare < partialInfo.size(); frameToCompare++) {
189 REPORTER_ASSERT(r, partialInfo[frameToCompare].fRequiredFrame
190 == frameInfo[frameToCompare].fRequiredFrame);
191 }
192
193 if (frameToCompare == frameInfo.size()) {
194 break;
195 }
Nigel Taoafea9c32018-08-01 15:00:32 +1000196
197 if (stream->getLength() == file->size()) {
198 ERRORF(r, "Should have found all frames for %s", path);
199 return;
200 }
201 stream->addNewData(1);
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500202 }
203}
204
scroggo19b91532016-10-24 09:03:26 -0700205DEF_TEST(Codec_partialAnim, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500206 auto path = "images/test640x479.gif";
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500207 sk_sp<SkData> file = GetResourceAsData(path);
scroggo19b91532016-10-24 09:03:26 -0700208 if (!file) {
209 return;
210 }
211
212 // This stream will be owned by fullCodec, but we hang on to the pointer
213 // to determine frame offsets.
Mike Reedede7bac2017-07-23 15:30:02 -0400214 std::unique_ptr<SkCodec> fullCodec(SkCodec::MakeFromStream(skstd::make_unique<SkMemoryStream>(file)));
scroggo19b91532016-10-24 09:03:26 -0700215 const auto info = standardize_info(fullCodec.get());
216
217 // frameByteCounts stores the number of bytes to decode a particular frame.
218 // - [0] is the number of bytes for the header
219 // - frames[i] requires frameByteCounts[i+1] bytes to decode
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400220 const std::vector<size_t> frameByteCounts = { 455, 69350, 1344, 1346, 1327 };
scroggo19b91532016-10-24 09:03:26 -0700221 std::vector<SkBitmap> frames;
scroggo19b91532016-10-24 09:03:26 -0700222 for (size_t i = 0; true; i++) {
scroggo19b91532016-10-24 09:03:26 -0700223 SkBitmap frame;
224 frame.allocPixels(info);
225
226 SkCodec::Options opts;
227 opts.fFrameIndex = i;
228 const SkCodec::Result result = fullCodec->getPixels(info, frame.getPixels(),
Leon Scroggins571b30f2017-07-11 17:35:31 +0000229 frame.rowBytes(), &opts);
scroggo19b91532016-10-24 09:03:26 -0700230
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500231 if (result == SkCodec::kIncompleteInput || result == SkCodec::kInvalidInput) {
scroggo19b91532016-10-24 09:03:26 -0700232 // We need to distinguish between a partial frame and no more frames.
233 // getFrameInfo lets us do this, since it tells the number of frames
234 // not considering whether they are complete.
235 // FIXME: Should we use a different Result?
236 if (fullCodec->getFrameInfo().size() > i) {
237 // This is a partial frame.
238 frames.push_back(frame);
239 }
240 break;
241 }
242
243 if (result != SkCodec::kSuccess) {
244 ERRORF(r, "Failed to decode frame %i from %s", i, path);
245 return;
246 }
247
248 frames.push_back(frame);
249 }
250
251 // Now decode frames partially, then completely, and compare to the original.
252 HaltingStream* haltingStream = new HaltingStream(file, frameByteCounts[0]);
Mike Reedede7bac2017-07-23 15:30:02 -0400253 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(
254 std::unique_ptr<SkStream>(haltingStream)));
scroggo19b91532016-10-24 09:03:26 -0700255 if (!partialCodec) {
256 ERRORF(r, "Failed to create a partial codec from %s with %i bytes out of %i",
257 path, frameByteCounts[0], file->size());
258 return;
259 }
260
261 SkASSERT(frameByteCounts.size() > frames.size());
262 for (size_t i = 0; i < frames.size(); i++) {
263 const size_t fullFrameBytes = frameByteCounts[i + 1];
264 const size_t firstHalf = fullFrameBytes / 2;
265 const size_t secondHalf = fullFrameBytes - firstHalf;
266
267 haltingStream->addNewData(firstHalf);
Leon Scroggins III3639faa2016-12-08 11:38:58 -0500268 auto frameInfo = partialCodec->getFrameInfo();
269 REPORTER_ASSERT(r, frameInfo.size() == i + 1);
270 REPORTER_ASSERT(r, !frameInfo[i].fFullyReceived);
scroggo19b91532016-10-24 09:03:26 -0700271
272 SkBitmap frame;
273 frame.allocPixels(info);
274
275 SkCodec::Options opts;
276 opts.fFrameIndex = i;
277 SkCodec::Result result = partialCodec->startIncrementalDecode(info,
278 frame.getPixels(), frame.rowBytes(), &opts);
279 if (result != SkCodec::kSuccess) {
280 ERRORF(r, "Failed to start incremental decode for %s on frame %i",
281 path, i);
282 return;
283 }
284
285 result = partialCodec->incrementalDecode();
286 REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
287
288 haltingStream->addNewData(secondHalf);
289 result = partialCodec->incrementalDecode();
290 REPORTER_ASSERT(r, SkCodec::kSuccess == result);
291
Leon Scroggins III3639faa2016-12-08 11:38:58 -0500292 frameInfo = partialCodec->getFrameInfo();
293 REPORTER_ASSERT(r, frameInfo.size() == i + 1);
294 REPORTER_ASSERT(r, frameInfo[i].fFullyReceived);
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -0500295 if (!compare_bitmaps(r, frames[i], frame)) {
296 ERRORF(r, "\tfailure was on frame %i", i);
297 SkString name = SkStringPrintf("expected_%i", i);
298 write_bm(name.c_str(), frames[i]);
299
300 name = SkStringPrintf("actual_%i", i);
301 write_bm(name.c_str(), frame);
302 }
scroggo19b91532016-10-24 09:03:26 -0700303 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700304}
305
306// Test that calling getPixels when an incremental decode has been
307// started (but not finished) makes the next call to incrementalDecode
308// require a call to startIncrementalDecode.
309static void test_interleaved(skiatest::Reporter* r, const char* name) {
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500310 sk_sp<SkData> file = GetResourceAsData(name);
scroggo19b91532016-10-24 09:03:26 -0700311 if (!file) {
312 return;
313 }
314 const size_t halfSize = file->size() / 2;
Mike Reedede7bac2017-07-23 15:30:02 -0400315 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(
316 skstd::make_unique<HaltingStream>(std::move(file), halfSize)));
scroggo8e6c7ad2016-09-16 08:20:38 -0700317 if (!partialCodec) {
318 ERRORF(r, "Failed to create codec for %s", name);
319 return;
320 }
321
Ben Wagner145dbcd2016-11-03 14:40:50 -0400322 const SkImageInfo info = standardize_info(partialCodec.get());
scroggo8e6c7ad2016-09-16 08:20:38 -0700323 SkBitmap incremental;
324 incremental.allocPixels(info);
325
326 const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info,
327 incremental.getPixels(), incremental.rowBytes());
328 if (startResult != SkCodec::kSuccess) {
329 ERRORF(r, "Failed to start incremental decode\n");
330 return;
331 }
332
333 SkCodec::Result result = partialCodec->incrementalDecode();
334 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
335
336 SkBitmap full;
337 full.allocPixels(info);
338 result = partialCodec->getPixels(info, full.getPixels(), full.rowBytes());
339 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
340
341 // Now incremental decode will fail
342 result = partialCodec->incrementalDecode();
343 REPORTER_ASSERT(r, result == SkCodec::kInvalidParameters);
344}
345
346DEF_TEST(Codec_rewind, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500347 test_interleaved(r, "images/plane.png");
348 test_interleaved(r, "images/plane_interlaced.png");
349 test_interleaved(r, "images/box.gif");
scroggo8e6c7ad2016-09-16 08:20:38 -0700350}
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500351
352// Modified version of the giflib logo, from
353// http://giflib.sourceforge.net/whatsinagif/bits_and_bytes.html
354// The global color map has been replaced with a local color map.
355static unsigned char gNoGlobalColorMap[] = {
356 // Header
357 0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
358
359 // Logical screen descriptor
360 0x0A, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x00,
361
362 // Image descriptor
363 0x2C, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x81,
364
365 // Local color table
366 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
367
368 // Image data
369 0x02, 0x16, 0x8C, 0x2D, 0x99, 0x87, 0x2A, 0x1C, 0xDC, 0x33, 0xA0, 0x02, 0x75,
370 0xEC, 0x95, 0xFA, 0xA8, 0xDE, 0x60, 0x8C, 0x04, 0x91, 0x4C, 0x01, 0x00,
371
372 // Trailer
373 0x3B,
374};
375
376// Test that a gif file truncated before its local color map behaves as expected.
377DEF_TEST(Codec_GifPreMap, r) {
378 sk_sp<SkData> data = SkData::MakeWithoutCopy(gNoGlobalColorMap, sizeof(gNoGlobalColorMap));
Mike Reedede7bac2017-07-23 15:30:02 -0400379 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500380 if (!codec) {
381 ERRORF(r, "failed to create codec");
382 return;
383 }
384
385 SkBitmap truth;
386 auto info = standardize_info(codec.get());
387 truth.allocPixels(info);
388
389 auto result = codec->getPixels(info, truth.getPixels(), truth.rowBytes());
390 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
391
392 // Truncate to 23 bytes, just before the color map. This should fail to decode.
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400393 //
394 // See also Codec_GifTruncated2 in GifTest.cpp for this magic 23.
Mike Reedede7bac2017-07-23 15:30:02 -0400395 codec = SkCodec::MakeFromData(SkData::MakeWithoutCopy(gNoGlobalColorMap, 23));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500396 REPORTER_ASSERT(r, codec);
397 if (codec) {
398 SkBitmap bm;
399 bm.allocPixels(info);
400 result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400401
402 // See the comments in Codec_GifTruncated2.
403#ifdef SK_HAS_WUFFS_LIBRARY
404 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
405#else
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500406 REPORTER_ASSERT(r, result == SkCodec::kInvalidInput);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400407#endif
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500408 }
409
410 // Again, truncate to 23 bytes, this time for an incremental decode. We
411 // cannot start an incremental decode until we have more data. If we did,
412 // we would be using the wrong color table.
413 HaltingStream* stream = new HaltingStream(data, 23);
Mike Reedede7bac2017-07-23 15:30:02 -0400414 codec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500415 REPORTER_ASSERT(r, codec);
416 if (codec) {
417 SkBitmap bm;
418 bm.allocPixels(info);
419 result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400420
421 // See the comments in Codec_GifTruncated2.
422#ifdef SK_HAS_WUFFS_LIBRARY
423 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
424
425 // Note that this is incrementalDecode, not startIncrementalDecode.
426 result = codec->incrementalDecode();
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500427 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
428
429 stream->addNewData(data->size());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400430#else
431 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
432
433 // Note that this is startIncrementalDecode, not incrementalDecode.
434 stream->addNewData(data->size());
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500435 result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
436 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400437#endif
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500438
439 result = codec->incrementalDecode();
440 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
441 compare_bitmaps(r, truth, bm);
442 }
443}
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400444
445DEF_TEST(Codec_emptyIDAT, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500446 const char* name = "images/baby_tux.png";
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400447 sk_sp<SkData> file = GetResourceAsData(name);
448 if (!file) {
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400449 return;
450 }
451
452 // Truncate to the beginning of the IDAT, immediately after the IDAT tag.
453 file = SkData::MakeSubset(file.get(), 0, 80);
454
Mike Reedede7bac2017-07-23 15:30:02 -0400455 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(std::move(file)));
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400456 if (!codec) {
457 ERRORF(r, "Failed to create a codec for %s", name);
458 return;
459 }
460
461 SkBitmap bm;
462 const auto info = standardize_info(codec.get());
463 bm.allocPixels(info);
464
465 const auto result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
466 REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
467}
Leon Scroggins III588fb042017-07-14 16:32:31 -0400468
469DEF_TEST(Codec_incomplete, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500470 for (const char* name : { "images/baby_tux.png",
471 "images/baby_tux.webp",
472 "images/CMYK.jpg",
473 "images/color_wheel.gif",
474 "images/google_chrome.ico",
475 "images/rle.bmp",
476 "images/mandrill.wbmp",
Leon Scroggins III588fb042017-07-14 16:32:31 -0400477 }) {
478 sk_sp<SkData> file = GetResourceAsData(name);
Bruce Wang61f36d32018-05-29 17:29:24 -0400479 if (!file) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400480 continue;
481 }
482
483 for (size_t len = 14; len <= file->size(); len += 5) {
484 SkCodec::Result result;
Mike Reedede7bac2017-07-23 15:30:02 -0400485 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(
486 skstd::make_unique<SkMemoryStream>(file->data(), len), &result));
Leon Scroggins III588fb042017-07-14 16:32:31 -0400487 if (codec) {
488 if (result != SkCodec::kSuccess) {
489 ERRORF(r, "Created an SkCodec for %s with %lu bytes, but "
490 "reported an error %i", name, len, result);
491 }
492 break;
493 }
494
495 if (SkCodec::kIncompleteInput != result) {
496 ERRORF(r, "Reported error %i for %s with %lu bytes",
497 result, name, len);
498 break;
499 }
500 }
501 }
502}