blob: 84bc03ed6bd71073aa096d61228b6790cecf0766 [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 III762ff972018-12-13 10:34:38 -050061static void test_partial(skiatest::Reporter* r, const char* name, const sk_sp<SkData>& file,
62 size_t minBytes, size_t increment) {
scroggo8e6c7ad2016-09-16 08:20:38 -070063 SkBitmap truth;
64 if (!create_truth(file, &truth)) {
65 ERRORF(r, "Failed to decode %s\n", name);
66 return;
67 }
68
scroggo8e6c7ad2016-09-16 08:20:38 -070069 // Now decode part of the file
Leon Scroggins III762ff972018-12-13 10:34:38 -050070 HaltingStream* stream = new HaltingStream(file, minBytes);
scroggo8e6c7ad2016-09-16 08:20:38 -070071
72 // Note that we cheat and hold on to a pointer to stream, though it is owned by
73 // partialCodec.
Leon Scroggins III762ff972018-12-13 10:34:38 -050074 auto partialCodec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
scroggo8e6c7ad2016-09-16 08:20:38 -070075 if (!partialCodec) {
Leon Scroggins III762ff972018-12-13 10:34:38 -050076 ERRORF(r, "Failed to create codec for %s with %zu bytes", name, minBytes);
scroggo8e6c7ad2016-09-16 08:20:38 -070077 return;
78 }
79
Ben Wagner145dbcd2016-11-03 14:40:50 -040080 const SkImageInfo info = standardize_info(partialCodec.get());
scroggo8e6c7ad2016-09-16 08:20:38 -070081 SkASSERT(info == truth.info());
82 SkBitmap incremental;
83 incremental.allocPixels(info);
84
scroggo19b91532016-10-24 09:03:26 -070085 while (true) {
86 const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info,
87 incremental.getPixels(), incremental.rowBytes());
88 if (startResult == SkCodec::kSuccess) {
89 break;
90 }
91
92 if (stream->isAllDataReceived()) {
93 ERRORF(r, "Failed to start incremental decode\n");
94 return;
95 }
96
Leon Scroggins III762ff972018-12-13 10:34:38 -050097 stream->addNewData(increment);
scroggo8e6c7ad2016-09-16 08:20:38 -070098 }
99
100 while (true) {
Leon Scroggins III762ff972018-12-13 10:34:38 -0500101 // This imitates how Chromium calls getFrameCount before resuming a decode.
102 // Without this line, the test passes. With it, it fails when skia_use_wuffs
103 // is true.
104 partialCodec->getFrameCount();
scroggo8e6c7ad2016-09-16 08:20:38 -0700105 const SkCodec::Result result = partialCodec->incrementalDecode();
106
scroggo19b91532016-10-24 09:03:26 -0700107 if (result == SkCodec::kSuccess) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700108 break;
109 }
110
scroggo8e6c7ad2016-09-16 08:20:38 -0700111 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
112
scroggo19b91532016-10-24 09:03:26 -0700113 if (stream->isAllDataReceived()) {
114 ERRORF(r, "Failed to completely decode %s", name);
115 return;
116 }
117
Leon Scroggins III762ff972018-12-13 10:34:38 -0500118 stream->addNewData(increment);
scroggo8e6c7ad2016-09-16 08:20:38 -0700119 }
120
121 // compare to original
scroggo19b91532016-10-24 09:03:26 -0700122 compare_bitmaps(r, truth, incremental);
scroggo8e6c7ad2016-09-16 08:20:38 -0700123}
124
Leon Scroggins III762ff972018-12-13 10:34:38 -0500125static void test_partial(skiatest::Reporter* r, const char* name, size_t minBytes = 0) {
126 sk_sp<SkData> file = GetResourceAsData(name);
127 if (!file) {
128 SkDebugf("missing resource %s\n", name);
129 return;
130 }
131
132 // This size is arbitrary, but deliberately different from the buffer size used by SkPngCodec.
133 constexpr size_t kIncrement = 1000;
134 test_partial(r, name, file, SkTMax(file->size() / 2, minBytes), kIncrement);
135}
136
scroggo8e6c7ad2016-09-16 08:20:38 -0700137DEF_TEST(Codec_partial, r) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400138#if 0
139 // FIXME (scroggo): SkPngCodec needs to use SkStreamBuffer in order to
140 // support incremental decoding.
Hal Canaryc465d132017-12-08 10:21:31 -0500141 test_partial(r, "images/plane.png");
142 test_partial(r, "images/plane_interlaced.png");
143 test_partial(r, "images/yellow_rose.png");
144 test_partial(r, "images/index8.png");
145 test_partial(r, "images/color_wheel.png");
146 test_partial(r, "images/mandrill_256.png");
147 test_partial(r, "images/mandrill_32.png");
148 test_partial(r, "images/arrow.png");
149 test_partial(r, "images/randPixels.png");
150 test_partial(r, "images/baby_tux.png");
Leon Scroggins III83239652017-04-21 13:47:12 -0400151#endif
Hal Canaryc465d132017-12-08 10:21:31 -0500152 test_partial(r, "images/box.gif");
153 test_partial(r, "images/randPixels.gif", 215);
154 test_partial(r, "images/color_wheel.gif");
scroggo19b91532016-10-24 09:03:26 -0700155}
156
Leon Scroggins III762ff972018-12-13 10:34:38 -0500157DEF_TEST(Codec_partialWuffs, r) {
158 const char* path = "images/alphabetAnim.gif";
159 auto file = GetResourceAsData(path);
160 if (!file) {
161 ERRORF(r, "missing %s", path);
162 } else {
163 // This is the end of the first frame. SkCodec will treat this as a
164 // single frame gif.
165 file = SkData::MakeSubset(file.get(), 0, 153);
166 // Start with 100 to get a partial decode, then add the rest of the
167 // first frame to decode a full image.
168 test_partial(r, path, file, 100, 53);
169 }
170}
171
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500172// Verify that when decoding an animated gif byte by byte we report the correct
173// fRequiredFrame as soon as getFrameInfo reports the frame.
174DEF_TEST(Codec_requiredFrame, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500175 auto path = "images/colorTables.gif";
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500176 sk_sp<SkData> file = GetResourceAsData(path);
177 if (!file) {
178 return;
179 }
180
Mike Reedede7bac2017-07-23 15:30:02 -0400181 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(file));
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500182 if (!codec) {
183 ERRORF(r, "Failed to create codec from %s", path);
184 return;
185 }
186
187 auto frameInfo = codec->getFrameInfo();
188 if (frameInfo.size() <= 1) {
189 ERRORF(r, "Test is uninteresting with 0 or 1 frames");
190 return;
191 }
192
193 HaltingStream* stream(nullptr);
194 std::unique_ptr<SkCodec> partialCodec(nullptr);
195 for (size_t i = 0; !partialCodec; i++) {
196 if (file->size() == i) {
197 ERRORF(r, "Should have created a partial codec for %s", path);
198 return;
199 }
200 stream = new HaltingStream(file, i);
Mike Reedede7bac2017-07-23 15:30:02 -0400201 partialCodec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500202 }
203
204 std::vector<SkCodec::FrameInfo> partialInfo;
205 size_t frameToCompare = 0;
Nigel Taoafea9c32018-08-01 15:00:32 +1000206 while (true) {
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500207 partialInfo = partialCodec->getFrameInfo();
208 for (; frameToCompare < partialInfo.size(); frameToCompare++) {
209 REPORTER_ASSERT(r, partialInfo[frameToCompare].fRequiredFrame
210 == frameInfo[frameToCompare].fRequiredFrame);
211 }
212
213 if (frameToCompare == frameInfo.size()) {
214 break;
215 }
Nigel Taoafea9c32018-08-01 15:00:32 +1000216
217 if (stream->getLength() == file->size()) {
218 ERRORF(r, "Should have found all frames for %s", path);
219 return;
220 }
221 stream->addNewData(1);
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500222 }
223}
224
scroggo19b91532016-10-24 09:03:26 -0700225DEF_TEST(Codec_partialAnim, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500226 auto path = "images/test640x479.gif";
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500227 sk_sp<SkData> file = GetResourceAsData(path);
scroggo19b91532016-10-24 09:03:26 -0700228 if (!file) {
229 return;
230 }
231
232 // This stream will be owned by fullCodec, but we hang on to the pointer
233 // to determine frame offsets.
Mike Reedede7bac2017-07-23 15:30:02 -0400234 std::unique_ptr<SkCodec> fullCodec(SkCodec::MakeFromStream(skstd::make_unique<SkMemoryStream>(file)));
scroggo19b91532016-10-24 09:03:26 -0700235 const auto info = standardize_info(fullCodec.get());
236
237 // frameByteCounts stores the number of bytes to decode a particular frame.
238 // - [0] is the number of bytes for the header
239 // - frames[i] requires frameByteCounts[i+1] bytes to decode
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400240 const std::vector<size_t> frameByteCounts = { 455, 69350, 1344, 1346, 1327 };
scroggo19b91532016-10-24 09:03:26 -0700241 std::vector<SkBitmap> frames;
scroggo19b91532016-10-24 09:03:26 -0700242 for (size_t i = 0; true; i++) {
scroggo19b91532016-10-24 09:03:26 -0700243 SkBitmap frame;
244 frame.allocPixels(info);
245
246 SkCodec::Options opts;
247 opts.fFrameIndex = i;
248 const SkCodec::Result result = fullCodec->getPixels(info, frame.getPixels(),
Leon Scroggins571b30f2017-07-11 17:35:31 +0000249 frame.rowBytes(), &opts);
scroggo19b91532016-10-24 09:03:26 -0700250
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500251 if (result == SkCodec::kIncompleteInput || result == SkCodec::kInvalidInput) {
scroggo19b91532016-10-24 09:03:26 -0700252 // We need to distinguish between a partial frame and no more frames.
253 // getFrameInfo lets us do this, since it tells the number of frames
254 // not considering whether they are complete.
255 // FIXME: Should we use a different Result?
256 if (fullCodec->getFrameInfo().size() > i) {
257 // This is a partial frame.
258 frames.push_back(frame);
259 }
260 break;
261 }
262
263 if (result != SkCodec::kSuccess) {
264 ERRORF(r, "Failed to decode frame %i from %s", i, path);
265 return;
266 }
267
268 frames.push_back(frame);
269 }
270
271 // Now decode frames partially, then completely, and compare to the original.
272 HaltingStream* haltingStream = new HaltingStream(file, frameByteCounts[0]);
Mike Reedede7bac2017-07-23 15:30:02 -0400273 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(
274 std::unique_ptr<SkStream>(haltingStream)));
scroggo19b91532016-10-24 09:03:26 -0700275 if (!partialCodec) {
276 ERRORF(r, "Failed to create a partial codec from %s with %i bytes out of %i",
277 path, frameByteCounts[0], file->size());
278 return;
279 }
280
281 SkASSERT(frameByteCounts.size() > frames.size());
282 for (size_t i = 0; i < frames.size(); i++) {
283 const size_t fullFrameBytes = frameByteCounts[i + 1];
284 const size_t firstHalf = fullFrameBytes / 2;
285 const size_t secondHalf = fullFrameBytes - firstHalf;
286
287 haltingStream->addNewData(firstHalf);
Leon Scroggins III3639faa2016-12-08 11:38:58 -0500288 auto frameInfo = partialCodec->getFrameInfo();
289 REPORTER_ASSERT(r, frameInfo.size() == i + 1);
290 REPORTER_ASSERT(r, !frameInfo[i].fFullyReceived);
scroggo19b91532016-10-24 09:03:26 -0700291
292 SkBitmap frame;
293 frame.allocPixels(info);
294
295 SkCodec::Options opts;
296 opts.fFrameIndex = i;
297 SkCodec::Result result = partialCodec->startIncrementalDecode(info,
298 frame.getPixels(), frame.rowBytes(), &opts);
299 if (result != SkCodec::kSuccess) {
300 ERRORF(r, "Failed to start incremental decode for %s on frame %i",
301 path, i);
302 return;
303 }
304
305 result = partialCodec->incrementalDecode();
306 REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
307
308 haltingStream->addNewData(secondHalf);
309 result = partialCodec->incrementalDecode();
310 REPORTER_ASSERT(r, SkCodec::kSuccess == result);
311
Leon Scroggins III3639faa2016-12-08 11:38:58 -0500312 frameInfo = partialCodec->getFrameInfo();
313 REPORTER_ASSERT(r, frameInfo.size() == i + 1);
314 REPORTER_ASSERT(r, frameInfo[i].fFullyReceived);
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -0500315 if (!compare_bitmaps(r, frames[i], frame)) {
316 ERRORF(r, "\tfailure was on frame %i", i);
317 SkString name = SkStringPrintf("expected_%i", i);
318 write_bm(name.c_str(), frames[i]);
319
320 name = SkStringPrintf("actual_%i", i);
321 write_bm(name.c_str(), frame);
322 }
scroggo19b91532016-10-24 09:03:26 -0700323 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700324}
325
326// Test that calling getPixels when an incremental decode has been
327// started (but not finished) makes the next call to incrementalDecode
328// require a call to startIncrementalDecode.
329static void test_interleaved(skiatest::Reporter* r, const char* name) {
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500330 sk_sp<SkData> file = GetResourceAsData(name);
scroggo19b91532016-10-24 09:03:26 -0700331 if (!file) {
332 return;
333 }
334 const size_t halfSize = file->size() / 2;
Mike Reedede7bac2017-07-23 15:30:02 -0400335 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(
336 skstd::make_unique<HaltingStream>(std::move(file), halfSize)));
scroggo8e6c7ad2016-09-16 08:20:38 -0700337 if (!partialCodec) {
338 ERRORF(r, "Failed to create codec for %s", name);
339 return;
340 }
341
Ben Wagner145dbcd2016-11-03 14:40:50 -0400342 const SkImageInfo info = standardize_info(partialCodec.get());
scroggo8e6c7ad2016-09-16 08:20:38 -0700343 SkBitmap incremental;
344 incremental.allocPixels(info);
345
346 const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info,
347 incremental.getPixels(), incremental.rowBytes());
348 if (startResult != SkCodec::kSuccess) {
349 ERRORF(r, "Failed to start incremental decode\n");
350 return;
351 }
352
353 SkCodec::Result result = partialCodec->incrementalDecode();
354 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
355
356 SkBitmap full;
357 full.allocPixels(info);
358 result = partialCodec->getPixels(info, full.getPixels(), full.rowBytes());
359 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
360
361 // Now incremental decode will fail
362 result = partialCodec->incrementalDecode();
363 REPORTER_ASSERT(r, result == SkCodec::kInvalidParameters);
364}
365
366DEF_TEST(Codec_rewind, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500367 test_interleaved(r, "images/plane.png");
368 test_interleaved(r, "images/plane_interlaced.png");
369 test_interleaved(r, "images/box.gif");
scroggo8e6c7ad2016-09-16 08:20:38 -0700370}
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500371
372// Modified version of the giflib logo, from
373// http://giflib.sourceforge.net/whatsinagif/bits_and_bytes.html
374// The global color map has been replaced with a local color map.
375static unsigned char gNoGlobalColorMap[] = {
376 // Header
377 0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
378
379 // Logical screen descriptor
380 0x0A, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x00,
381
382 // Image descriptor
383 0x2C, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x81,
384
385 // Local color table
386 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
387
388 // Image data
389 0x02, 0x16, 0x8C, 0x2D, 0x99, 0x87, 0x2A, 0x1C, 0xDC, 0x33, 0xA0, 0x02, 0x75,
390 0xEC, 0x95, 0xFA, 0xA8, 0xDE, 0x60, 0x8C, 0x04, 0x91, 0x4C, 0x01, 0x00,
391
392 // Trailer
393 0x3B,
394};
395
396// Test that a gif file truncated before its local color map behaves as expected.
397DEF_TEST(Codec_GifPreMap, r) {
398 sk_sp<SkData> data = SkData::MakeWithoutCopy(gNoGlobalColorMap, sizeof(gNoGlobalColorMap));
Mike Reedede7bac2017-07-23 15:30:02 -0400399 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500400 if (!codec) {
401 ERRORF(r, "failed to create codec");
402 return;
403 }
404
405 SkBitmap truth;
406 auto info = standardize_info(codec.get());
407 truth.allocPixels(info);
408
409 auto result = codec->getPixels(info, truth.getPixels(), truth.rowBytes());
410 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
411
412 // Truncate to 23 bytes, just before the color map. This should fail to decode.
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400413 //
414 // See also Codec_GifTruncated2 in GifTest.cpp for this magic 23.
Mike Reedede7bac2017-07-23 15:30:02 -0400415 codec = SkCodec::MakeFromData(SkData::MakeWithoutCopy(gNoGlobalColorMap, 23));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500416 REPORTER_ASSERT(r, codec);
417 if (codec) {
418 SkBitmap bm;
419 bm.allocPixels(info);
420 result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400421
422 // See the comments in Codec_GifTruncated2.
423#ifdef SK_HAS_WUFFS_LIBRARY
424 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
425#else
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500426 REPORTER_ASSERT(r, result == SkCodec::kInvalidInput);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400427#endif
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500428 }
429
430 // Again, truncate to 23 bytes, this time for an incremental decode. We
431 // cannot start an incremental decode until we have more data. If we did,
432 // we would be using the wrong color table.
433 HaltingStream* stream = new HaltingStream(data, 23);
Mike Reedede7bac2017-07-23 15:30:02 -0400434 codec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500435 REPORTER_ASSERT(r, codec);
436 if (codec) {
437 SkBitmap bm;
438 bm.allocPixels(info);
439 result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400440
441 // See the comments in Codec_GifTruncated2.
442#ifdef SK_HAS_WUFFS_LIBRARY
443 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
444
445 // Note that this is incrementalDecode, not startIncrementalDecode.
446 result = codec->incrementalDecode();
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500447 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
448
449 stream->addNewData(data->size());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400450#else
451 REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
452
453 // Note that this is startIncrementalDecode, not incrementalDecode.
454 stream->addNewData(data->size());
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500455 result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
456 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400457#endif
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500458
459 result = codec->incrementalDecode();
460 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
461 compare_bitmaps(r, truth, bm);
462 }
463}
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400464
465DEF_TEST(Codec_emptyIDAT, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500466 const char* name = "images/baby_tux.png";
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400467 sk_sp<SkData> file = GetResourceAsData(name);
468 if (!file) {
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400469 return;
470 }
471
472 // Truncate to the beginning of the IDAT, immediately after the IDAT tag.
473 file = SkData::MakeSubset(file.get(), 0, 80);
474
Mike Reedede7bac2017-07-23 15:30:02 -0400475 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(std::move(file)));
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400476 if (!codec) {
477 ERRORF(r, "Failed to create a codec for %s", name);
478 return;
479 }
480
481 SkBitmap bm;
482 const auto info = standardize_info(codec.get());
483 bm.allocPixels(info);
484
485 const auto result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
486 REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
487}
Leon Scroggins III588fb042017-07-14 16:32:31 -0400488
489DEF_TEST(Codec_incomplete, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500490 for (const char* name : { "images/baby_tux.png",
491 "images/baby_tux.webp",
492 "images/CMYK.jpg",
493 "images/color_wheel.gif",
494 "images/google_chrome.ico",
495 "images/rle.bmp",
496 "images/mandrill.wbmp",
Leon Scroggins III588fb042017-07-14 16:32:31 -0400497 }) {
498 sk_sp<SkData> file = GetResourceAsData(name);
Bruce Wang61f36d32018-05-29 17:29:24 -0400499 if (!file) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400500 continue;
501 }
502
503 for (size_t len = 14; len <= file->size(); len += 5) {
504 SkCodec::Result result;
Mike Reedede7bac2017-07-23 15:30:02 -0400505 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(
506 skstd::make_unique<SkMemoryStream>(file->data(), len), &result));
Leon Scroggins III588fb042017-07-14 16:32:31 -0400507 if (codec) {
508 if (result != SkCodec::kSuccess) {
509 ERRORF(r, "Created an SkCodec for %s with %lu bytes, but "
510 "reported an error %i", name, len, result);
511 }
512 break;
513 }
514
515 if (SkCodec::kIncompleteInput != result) {
516 ERRORF(r, "Reported error %i for %s with %lu bytes",
517 result, name, len);
518 break;
519 }
520 }
521 }
522}