blob: 0ff5435e13cc7f46263480b27c34d2627e6067f3 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/codec/SkCodec.h"
9#include "include/core/SkBitmap.h"
10#include "include/core/SkData.h"
11#include "include/core/SkImageInfo.h"
12#include "include/core/SkRefCnt.h"
13#include "include/core/SkStream.h"
Ben Wagner9707a7e2019-05-06 17:17:19 -040014#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "include/core/SkTypes.h"
16#include "src/core/SkMakeUnique.h"
17#include "tests/CodecPriv.h"
18#include "tests/FakeStreams.h"
19#include "tests/Test.h"
20#include "tools/Resources.h"
Ben Wagner1a462bd2018-03-12 13:46:21 -040021
Ben Wagnerb607a8f2018-03-12 13:46:21 -040022#include <cstring>
Ben Wagner9707a7e2019-05-06 17:17:19 -040023#include <initializer_list>
Ben Wagnerb607a8f2018-03-12 13:46:21 -040024#include <memory>
25#include <utility>
26#include <vector>
27
scroggo8e6c7ad2016-09-16 08:20:38 -070028static SkImageInfo standardize_info(SkCodec* codec) {
29 SkImageInfo defaultInfo = codec->getInfo();
30 // Note: This drops the SkColorSpace, allowing the equality check between two
31 // different codecs created from the same file to have the same SkImageInfo.
32 return SkImageInfo::MakeN32Premul(defaultInfo.width(), defaultInfo.height());
33}
34
35static bool create_truth(sk_sp<SkData> data, SkBitmap* dst) {
Mike Reedede7bac2017-07-23 15:30:02 -040036 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(std::move(data)));
scroggo8e6c7ad2016-09-16 08:20:38 -070037 if (!codec) {
38 return false;
39 }
40
Ben Wagner145dbcd2016-11-03 14:40:50 -040041 const SkImageInfo info = standardize_info(codec.get());
scroggo8e6c7ad2016-09-16 08:20:38 -070042 dst->allocPixels(info);
43 return SkCodec::kSuccess == codec->getPixels(info, dst->getPixels(), dst->rowBytes());
44}
45
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -050046static bool compare_bitmaps(skiatest::Reporter* r, const SkBitmap& bm1, const SkBitmap& bm2) {
scroggo19b91532016-10-24 09:03:26 -070047 const SkImageInfo& info = bm1.info();
48 if (info != bm2.info()) {
49 ERRORF(r, "Bitmaps have different image infos!");
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -050050 return false;
scroggo19b91532016-10-24 09:03:26 -070051 }
52 const size_t rowBytes = info.minRowBytes();
53 for (int i = 0; i < info.height(); i++) {
nagarajan.n0ec0bf02017-10-11 10:41:27 +053054 if (memcmp(bm1.getAddr(0, i), bm2.getAddr(0, i), rowBytes)) {
55 ERRORF(r, "Bitmaps have different pixels, starting on line %i!", i);
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -050056 return false;
nagarajan.n0ec0bf02017-10-11 10:41:27 +053057 }
scroggo19b91532016-10-24 09:03:26 -070058 }
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -050059
60 return true;
scroggo19b91532016-10-24 09:03:26 -070061}
62
Leon Scroggins III762ff972018-12-13 10:34:38 -050063static void test_partial(skiatest::Reporter* r, const char* name, const sk_sp<SkData>& file,
64 size_t minBytes, size_t increment) {
scroggo8e6c7ad2016-09-16 08:20:38 -070065 SkBitmap truth;
66 if (!create_truth(file, &truth)) {
67 ERRORF(r, "Failed to decode %s\n", name);
68 return;
69 }
70
scroggo8e6c7ad2016-09-16 08:20:38 -070071 // Now decode part of the file
Leon Scroggins III762ff972018-12-13 10:34:38 -050072 HaltingStream* stream = new HaltingStream(file, minBytes);
scroggo8e6c7ad2016-09-16 08:20:38 -070073
74 // Note that we cheat and hold on to a pointer to stream, though it is owned by
75 // partialCodec.
Leon Scroggins III762ff972018-12-13 10:34:38 -050076 auto partialCodec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
scroggo8e6c7ad2016-09-16 08:20:38 -070077 if (!partialCodec) {
Leon Scroggins III762ff972018-12-13 10:34:38 -050078 ERRORF(r, "Failed to create codec for %s with %zu bytes", name, minBytes);
scroggo8e6c7ad2016-09-16 08:20:38 -070079 return;
80 }
81
Ben Wagner145dbcd2016-11-03 14:40:50 -040082 const SkImageInfo info = standardize_info(partialCodec.get());
scroggo8e6c7ad2016-09-16 08:20:38 -070083 SkASSERT(info == truth.info());
84 SkBitmap incremental;
85 incremental.allocPixels(info);
86
scroggo19b91532016-10-24 09:03:26 -070087 while (true) {
88 const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info,
89 incremental.getPixels(), incremental.rowBytes());
90 if (startResult == SkCodec::kSuccess) {
91 break;
92 }
93
94 if (stream->isAllDataReceived()) {
95 ERRORF(r, "Failed to start incremental decode\n");
96 return;
97 }
98
Leon Scroggins III762ff972018-12-13 10:34:38 -050099 stream->addNewData(increment);
scroggo8e6c7ad2016-09-16 08:20:38 -0700100 }
101
102 while (true) {
Leon Scroggins III762ff972018-12-13 10:34:38 -0500103 // This imitates how Chromium calls getFrameCount before resuming a decode.
Leon Scroggins III762ff972018-12-13 10:34:38 -0500104 partialCodec->getFrameCount();
Nigel Tao1f1cd1f2019-06-22 17:35:38 +1000105
scroggo8e6c7ad2016-09-16 08:20:38 -0700106 const SkCodec::Result result = partialCodec->incrementalDecode();
107
scroggo19b91532016-10-24 09:03:26 -0700108 if (result == SkCodec::kSuccess) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700109 break;
110 }
111
scroggo8e6c7ad2016-09-16 08:20:38 -0700112 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
113
scroggo19b91532016-10-24 09:03:26 -0700114 if (stream->isAllDataReceived()) {
115 ERRORF(r, "Failed to completely decode %s", name);
116 return;
117 }
118
Leon Scroggins III762ff972018-12-13 10:34:38 -0500119 stream->addNewData(increment);
scroggo8e6c7ad2016-09-16 08:20:38 -0700120 }
121
122 // compare to original
scroggo19b91532016-10-24 09:03:26 -0700123 compare_bitmaps(r, truth, incremental);
scroggo8e6c7ad2016-09-16 08:20:38 -0700124}
125
Leon Scroggins III762ff972018-12-13 10:34:38 -0500126static void test_partial(skiatest::Reporter* r, const char* name, size_t minBytes = 0) {
127 sk_sp<SkData> file = GetResourceAsData(name);
128 if (!file) {
129 SkDebugf("missing resource %s\n", name);
130 return;
131 }
132
133 // This size is arbitrary, but deliberately different from the buffer size used by SkPngCodec.
134 constexpr size_t kIncrement = 1000;
135 test_partial(r, name, file, SkTMax(file->size() / 2, minBytes), kIncrement);
136}
137
scroggo8e6c7ad2016-09-16 08:20:38 -0700138DEF_TEST(Codec_partial, r) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400139#if 0
140 // FIXME (scroggo): SkPngCodec needs to use SkStreamBuffer in order to
141 // support incremental decoding.
Hal Canaryc465d132017-12-08 10:21:31 -0500142 test_partial(r, "images/plane.png");
143 test_partial(r, "images/plane_interlaced.png");
144 test_partial(r, "images/yellow_rose.png");
145 test_partial(r, "images/index8.png");
146 test_partial(r, "images/color_wheel.png");
147 test_partial(r, "images/mandrill_256.png");
148 test_partial(r, "images/mandrill_32.png");
149 test_partial(r, "images/arrow.png");
150 test_partial(r, "images/randPixels.png");
151 test_partial(r, "images/baby_tux.png");
Leon Scroggins III83239652017-04-21 13:47:12 -0400152#endif
Hal Canaryc465d132017-12-08 10:21:31 -0500153 test_partial(r, "images/box.gif");
154 test_partial(r, "images/randPixels.gif", 215);
155 test_partial(r, "images/color_wheel.gif");
scroggo19b91532016-10-24 09:03:26 -0700156}
157
Leon Scroggins III762ff972018-12-13 10:34:38 -0500158DEF_TEST(Codec_partialWuffs, r) {
159 const char* path = "images/alphabetAnim.gif";
160 auto file = GetResourceAsData(path);
161 if (!file) {
162 ERRORF(r, "missing %s", path);
163 } else {
164 // This is the end of the first frame. SkCodec will treat this as a
165 // single frame gif.
166 file = SkData::MakeSubset(file.get(), 0, 153);
167 // Start with 100 to get a partial decode, then add the rest of the
168 // first frame to decode a full image.
169 test_partial(r, path, file, 100, 53);
170 }
171}
172
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500173// Verify that when decoding an animated gif byte by byte we report the correct
174// fRequiredFrame as soon as getFrameInfo reports the frame.
175DEF_TEST(Codec_requiredFrame, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500176 auto path = "images/colorTables.gif";
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500177 sk_sp<SkData> file = GetResourceAsData(path);
178 if (!file) {
179 return;
180 }
181
Mike Reedede7bac2017-07-23 15:30:02 -0400182 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(file));
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500183 if (!codec) {
184 ERRORF(r, "Failed to create codec from %s", path);
185 return;
186 }
187
188 auto frameInfo = codec->getFrameInfo();
189 if (frameInfo.size() <= 1) {
190 ERRORF(r, "Test is uninteresting with 0 or 1 frames");
191 return;
192 }
193
194 HaltingStream* stream(nullptr);
195 std::unique_ptr<SkCodec> partialCodec(nullptr);
196 for (size_t i = 0; !partialCodec; i++) {
197 if (file->size() == i) {
198 ERRORF(r, "Should have created a partial codec for %s", path);
199 return;
200 }
201 stream = new HaltingStream(file, i);
Mike Reedede7bac2017-07-23 15:30:02 -0400202 partialCodec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500203 }
204
205 std::vector<SkCodec::FrameInfo> partialInfo;
206 size_t frameToCompare = 0;
Nigel Taoafea9c32018-08-01 15:00:32 +1000207 while (true) {
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500208 partialInfo = partialCodec->getFrameInfo();
209 for (; frameToCompare < partialInfo.size(); frameToCompare++) {
210 REPORTER_ASSERT(r, partialInfo[frameToCompare].fRequiredFrame
211 == frameInfo[frameToCompare].fRequiredFrame);
212 }
213
214 if (frameToCompare == frameInfo.size()) {
215 break;
216 }
Nigel Taoafea9c32018-08-01 15:00:32 +1000217
218 if (stream->getLength() == file->size()) {
219 ERRORF(r, "Should have found all frames for %s", path);
220 return;
221 }
222 stream->addNewData(1);
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500223 }
224}
225
scroggo19b91532016-10-24 09:03:26 -0700226DEF_TEST(Codec_partialAnim, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500227 auto path = "images/test640x479.gif";
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500228 sk_sp<SkData> file = GetResourceAsData(path);
scroggo19b91532016-10-24 09:03:26 -0700229 if (!file) {
230 return;
231 }
232
233 // This stream will be owned by fullCodec, but we hang on to the pointer
234 // to determine frame offsets.
Mike Reedede7bac2017-07-23 15:30:02 -0400235 std::unique_ptr<SkCodec> fullCodec(SkCodec::MakeFromStream(skstd::make_unique<SkMemoryStream>(file)));
scroggo19b91532016-10-24 09:03:26 -0700236 const auto info = standardize_info(fullCodec.get());
237
238 // frameByteCounts stores the number of bytes to decode a particular frame.
239 // - [0] is the number of bytes for the header
240 // - frames[i] requires frameByteCounts[i+1] bytes to decode
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400241 const std::vector<size_t> frameByteCounts = { 455, 69350, 1344, 1346, 1327 };
scroggo19b91532016-10-24 09:03:26 -0700242 std::vector<SkBitmap> frames;
scroggo19b91532016-10-24 09:03:26 -0700243 for (size_t i = 0; true; i++) {
scroggo19b91532016-10-24 09:03:26 -0700244 SkBitmap frame;
245 frame.allocPixels(info);
246
247 SkCodec::Options opts;
248 opts.fFrameIndex = i;
249 const SkCodec::Result result = fullCodec->getPixels(info, frame.getPixels(),
Leon Scroggins571b30f2017-07-11 17:35:31 +0000250 frame.rowBytes(), &opts);
scroggo19b91532016-10-24 09:03:26 -0700251
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500252 if (result == SkCodec::kIncompleteInput || result == SkCodec::kInvalidInput) {
scroggo19b91532016-10-24 09:03:26 -0700253 // We need to distinguish between a partial frame and no more frames.
254 // getFrameInfo lets us do this, since it tells the number of frames
255 // not considering whether they are complete.
256 // FIXME: Should we use a different Result?
257 if (fullCodec->getFrameInfo().size() > i) {
258 // This is a partial frame.
259 frames.push_back(frame);
260 }
261 break;
262 }
263
264 if (result != SkCodec::kSuccess) {
265 ERRORF(r, "Failed to decode frame %i from %s", i, path);
266 return;
267 }
268
269 frames.push_back(frame);
270 }
271
272 // Now decode frames partially, then completely, and compare to the original.
273 HaltingStream* haltingStream = new HaltingStream(file, frameByteCounts[0]);
Mike Reedede7bac2017-07-23 15:30:02 -0400274 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(
275 std::unique_ptr<SkStream>(haltingStream)));
scroggo19b91532016-10-24 09:03:26 -0700276 if (!partialCodec) {
277 ERRORF(r, "Failed to create a partial codec from %s with %i bytes out of %i",
278 path, frameByteCounts[0], file->size());
279 return;
280 }
281
282 SkASSERT(frameByteCounts.size() > frames.size());
283 for (size_t i = 0; i < frames.size(); i++) {
284 const size_t fullFrameBytes = frameByteCounts[i + 1];
285 const size_t firstHalf = fullFrameBytes / 2;
286 const size_t secondHalf = fullFrameBytes - firstHalf;
287
288 haltingStream->addNewData(firstHalf);
Leon Scroggins III3639faa2016-12-08 11:38:58 -0500289 auto frameInfo = partialCodec->getFrameInfo();
290 REPORTER_ASSERT(r, frameInfo.size() == i + 1);
291 REPORTER_ASSERT(r, !frameInfo[i].fFullyReceived);
scroggo19b91532016-10-24 09:03:26 -0700292
293 SkBitmap frame;
294 frame.allocPixels(info);
295
296 SkCodec::Options opts;
297 opts.fFrameIndex = i;
298 SkCodec::Result result = partialCodec->startIncrementalDecode(info,
299 frame.getPixels(), frame.rowBytes(), &opts);
300 if (result != SkCodec::kSuccess) {
301 ERRORF(r, "Failed to start incremental decode for %s on frame %i",
302 path, i);
303 return;
304 }
305
306 result = partialCodec->incrementalDecode();
307 REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
308
309 haltingStream->addNewData(secondHalf);
310 result = partialCodec->incrementalDecode();
311 REPORTER_ASSERT(r, SkCodec::kSuccess == result);
312
Leon Scroggins III3639faa2016-12-08 11:38:58 -0500313 frameInfo = partialCodec->getFrameInfo();
314 REPORTER_ASSERT(r, frameInfo.size() == i + 1);
315 REPORTER_ASSERT(r, frameInfo[i].fFullyReceived);
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -0500316 if (!compare_bitmaps(r, frames[i], frame)) {
317 ERRORF(r, "\tfailure was on frame %i", i);
318 SkString name = SkStringPrintf("expected_%i", i);
319 write_bm(name.c_str(), frames[i]);
320
321 name = SkStringPrintf("actual_%i", i);
322 write_bm(name.c_str(), frame);
323 }
scroggo19b91532016-10-24 09:03:26 -0700324 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700325}
326
327// Test that calling getPixels when an incremental decode has been
328// started (but not finished) makes the next call to incrementalDecode
329// require a call to startIncrementalDecode.
330static void test_interleaved(skiatest::Reporter* r, const char* name) {
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500331 sk_sp<SkData> file = GetResourceAsData(name);
scroggo19b91532016-10-24 09:03:26 -0700332 if (!file) {
333 return;
334 }
335 const size_t halfSize = file->size() / 2;
Mike Reedede7bac2017-07-23 15:30:02 -0400336 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(
337 skstd::make_unique<HaltingStream>(std::move(file), halfSize)));
scroggo8e6c7ad2016-09-16 08:20:38 -0700338 if (!partialCodec) {
339 ERRORF(r, "Failed to create codec for %s", name);
340 return;
341 }
342
Ben Wagner145dbcd2016-11-03 14:40:50 -0400343 const SkImageInfo info = standardize_info(partialCodec.get());
scroggo8e6c7ad2016-09-16 08:20:38 -0700344 SkBitmap incremental;
345 incremental.allocPixels(info);
346
347 const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info,
348 incremental.getPixels(), incremental.rowBytes());
349 if (startResult != SkCodec::kSuccess) {
350 ERRORF(r, "Failed to start incremental decode\n");
351 return;
352 }
353
354 SkCodec::Result result = partialCodec->incrementalDecode();
355 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
356
357 SkBitmap full;
358 full.allocPixels(info);
359 result = partialCodec->getPixels(info, full.getPixels(), full.rowBytes());
360 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
361
362 // Now incremental decode will fail
363 result = partialCodec->incrementalDecode();
364 REPORTER_ASSERT(r, result == SkCodec::kInvalidParameters);
365}
366
367DEF_TEST(Codec_rewind, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500368 test_interleaved(r, "images/plane.png");
369 test_interleaved(r, "images/plane_interlaced.png");
370 test_interleaved(r, "images/box.gif");
scroggo8e6c7ad2016-09-16 08:20:38 -0700371}
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500372
373// Modified version of the giflib logo, from
374// http://giflib.sourceforge.net/whatsinagif/bits_and_bytes.html
375// The global color map has been replaced with a local color map.
376static unsigned char gNoGlobalColorMap[] = {
377 // Header
378 0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
379
380 // Logical screen descriptor
381 0x0A, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x00,
382
383 // Image descriptor
384 0x2C, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x81,
385
386 // Local color table
387 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
388
389 // Image data
390 0x02, 0x16, 0x8C, 0x2D, 0x99, 0x87, 0x2A, 0x1C, 0xDC, 0x33, 0xA0, 0x02, 0x75,
391 0xEC, 0x95, 0xFA, 0xA8, 0xDE, 0x60, 0x8C, 0x04, 0x91, 0x4C, 0x01, 0x00,
392
393 // Trailer
394 0x3B,
395};
396
397// Test that a gif file truncated before its local color map behaves as expected.
398DEF_TEST(Codec_GifPreMap, r) {
399 sk_sp<SkData> data = SkData::MakeWithoutCopy(gNoGlobalColorMap, sizeof(gNoGlobalColorMap));
Mike Reedede7bac2017-07-23 15:30:02 -0400400 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500401 if (!codec) {
402 ERRORF(r, "failed to create codec");
403 return;
404 }
405
406 SkBitmap truth;
407 auto info = standardize_info(codec.get());
408 truth.allocPixels(info);
409
410 auto result = codec->getPixels(info, truth.getPixels(), truth.rowBytes());
411 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
412
413 // Truncate to 23 bytes, just before the color map. This should fail to decode.
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400414 //
415 // See also Codec_GifTruncated2 in GifTest.cpp for this magic 23.
Mike Reedede7bac2017-07-23 15:30:02 -0400416 codec = SkCodec::MakeFromData(SkData::MakeWithoutCopy(gNoGlobalColorMap, 23));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500417 REPORTER_ASSERT(r, codec);
418 if (codec) {
419 SkBitmap bm;
420 bm.allocPixels(info);
421 result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400422
423 // See the comments in Codec_GifTruncated2.
424#ifdef SK_HAS_WUFFS_LIBRARY
425 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
426#else
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500427 REPORTER_ASSERT(r, result == SkCodec::kInvalidInput);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400428#endif
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500429 }
430
431 // Again, truncate to 23 bytes, this time for an incremental decode. We
432 // cannot start an incremental decode until we have more data. If we did,
433 // we would be using the wrong color table.
434 HaltingStream* stream = new HaltingStream(data, 23);
Mike Reedede7bac2017-07-23 15:30:02 -0400435 codec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500436 REPORTER_ASSERT(r, codec);
437 if (codec) {
438 SkBitmap bm;
439 bm.allocPixels(info);
440 result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400441
442 // See the comments in Codec_GifTruncated2.
443#ifdef SK_HAS_WUFFS_LIBRARY
444 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
445
446 // Note that this is incrementalDecode, not startIncrementalDecode.
447 result = codec->incrementalDecode();
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500448 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
449
450 stream->addNewData(data->size());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400451#else
452 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
453
454 // Note that this is startIncrementalDecode, not incrementalDecode.
455 stream->addNewData(data->size());
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500456 result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
457 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400458#endif
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500459
460 result = codec->incrementalDecode();
461 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
462 compare_bitmaps(r, truth, bm);
463 }
464}
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400465
466DEF_TEST(Codec_emptyIDAT, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500467 const char* name = "images/baby_tux.png";
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400468 sk_sp<SkData> file = GetResourceAsData(name);
469 if (!file) {
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400470 return;
471 }
472
473 // Truncate to the beginning of the IDAT, immediately after the IDAT tag.
474 file = SkData::MakeSubset(file.get(), 0, 80);
475
Mike Reedede7bac2017-07-23 15:30:02 -0400476 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(std::move(file)));
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400477 if (!codec) {
478 ERRORF(r, "Failed to create a codec for %s", name);
479 return;
480 }
481
482 SkBitmap bm;
483 const auto info = standardize_info(codec.get());
484 bm.allocPixels(info);
485
486 const auto result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
487 REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
488}
Leon Scroggins III588fb042017-07-14 16:32:31 -0400489
490DEF_TEST(Codec_incomplete, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500491 for (const char* name : { "images/baby_tux.png",
492 "images/baby_tux.webp",
493 "images/CMYK.jpg",
494 "images/color_wheel.gif",
495 "images/google_chrome.ico",
496 "images/rle.bmp",
497 "images/mandrill.wbmp",
Leon Scroggins III588fb042017-07-14 16:32:31 -0400498 }) {
499 sk_sp<SkData> file = GetResourceAsData(name);
Bruce Wang61f36d32018-05-29 17:29:24 -0400500 if (!file) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400501 continue;
502 }
503
504 for (size_t len = 14; len <= file->size(); len += 5) {
505 SkCodec::Result result;
Mike Reedede7bac2017-07-23 15:30:02 -0400506 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(
507 skstd::make_unique<SkMemoryStream>(file->data(), len), &result));
Leon Scroggins III588fb042017-07-14 16:32:31 -0400508 if (codec) {
509 if (result != SkCodec::kSuccess) {
510 ERRORF(r, "Created an SkCodec for %s with %lu bytes, but "
511 "reported an error %i", name, len, result);
512 }
513 break;
514 }
515
516 if (SkCodec::kIncompleteInput != result) {
517 ERRORF(r, "Reported error %i for %s with %lu bytes",
518 result, name, len);
519 break;
520 }
521 }
522 }
523}