blob: af2d303be86cc7b401428206801f0ea64bd4584b [file] [log] [blame]
halcanary@google.com29d4e632013-10-11 18:21:56 +00001/*
2 * Copyright 2013 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
msarett7f7ec202016-03-01 12:12:27 -08008#include "CodecPriv.h"
scroggo9d214292015-05-14 14:44:13 -07009#include "Resources.h"
msarett7f7ec202016-03-01 12:12:27 -080010#include "SkAndroidCodec.h"
halcanary@google.com29d4e632013-10-11 18:21:56 +000011#include "SkBitmap.h"
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -040012#include "SkCanvas.h"
halcanary@google.com29d4e632013-10-11 18:21:56 +000013#include "SkData.h"
halcanary@google.com29d4e632013-10-11 18:21:56 +000014#include "SkImage.h"
15#include "SkStream.h"
msarett7f7ec202016-03-01 12:12:27 -080016#include "SkTypes.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000017#include "Test.h"
halcanary@google.com29d4e632013-10-11 18:21:56 +000018
tfarina@chromium.org58674812014-01-21 23:39:22 +000019static unsigned char gGIFData[] = {
20 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x03, 0x00, 0x03, 0x00, 0xe3, 0x08,
21 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00,
22 0xff, 0x80, 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
23 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
24 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
25 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x04,
26 0x07, 0x50, 0x1c, 0x43, 0x40, 0x41, 0x23, 0x44, 0x00, 0x3b
27};
28
29static unsigned char gGIFDataNoColormap[] = {
Leon Scroggins III3fc97d72016-12-09 16:39:33 -050030 // Header
31 0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
32 // Screen descriptor
33 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
34 // Graphics control extension
35 0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00, 0x01, 0x00,
36 // Image descriptor
37 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
38 // Image data
39 0x02, 0x02, 0x4c, 0x01, 0x00,
40 // Trailer
41 0x3b
tfarina@chromium.org58674812014-01-21 23:39:22 +000042};
43
44static unsigned char gInterlacedGIF[] = {
45 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x09, 0x00, 0x09, 0x00, 0xe3, 0x08, 0x00,
46 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80,
47 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
48 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00,
50 0x00, 0x09, 0x00, 0x09, 0x00, 0x40, 0x04, 0x1b, 0x50, 0x1c, 0x23, 0xe9, 0x44,
51 0x23, 0x60, 0x9d, 0x09, 0x28, 0x1e, 0xf8, 0x6d, 0x64, 0x56, 0x9d, 0x53, 0xa8,
52 0x7e, 0xa8, 0x65, 0x94, 0x5c, 0xb0, 0x8a, 0x45, 0x04, 0x00, 0x3b
53};
halcanary@google.com29d4e632013-10-11 18:21:56 +000054
55static void test_gif_data_no_colormap(skiatest::Reporter* r,
tfarina@chromium.org58674812014-01-21 23:39:22 +000056 void* data,
57 size_t size) {
halcanary@google.com29d4e632013-10-11 18:21:56 +000058 SkBitmap bm;
msarett7f7ec202016-03-01 12:12:27 -080059 bool imageDecodeSuccess = decode_memory(data, size, &bm);
halcanary@google.com29d4e632013-10-11 18:21:56 +000060 REPORTER_ASSERT(r, imageDecodeSuccess);
61 REPORTER_ASSERT(r, bm.width() == 1);
62 REPORTER_ASSERT(r, bm.height() == 1);
63 REPORTER_ASSERT(r, !(bm.empty()));
64 if (!(bm.empty())) {
scroggo19b91532016-10-24 09:03:26 -070065 REPORTER_ASSERT(r, bm.getColor(0, 0) == 0x00000000);
halcanary@google.com29d4e632013-10-11 18:21:56 +000066 }
67}
68static void test_gif_data(skiatest::Reporter* r, void* data, size_t size) {
69 SkBitmap bm;
msarett7f7ec202016-03-01 12:12:27 -080070 bool imageDecodeSuccess = decode_memory(data, size, &bm);
halcanary@google.com29d4e632013-10-11 18:21:56 +000071 REPORTER_ASSERT(r, imageDecodeSuccess);
72 REPORTER_ASSERT(r, bm.width() == 3);
73 REPORTER_ASSERT(r, bm.height() == 3);
74 REPORTER_ASSERT(r, !(bm.empty()));
75 if (!(bm.empty())) {
76 REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
77 REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
78 REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
79 REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
80 REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
81 REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
82 REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
83 REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
84 REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
85 }
86}
msarett7f7ec202016-03-01 12:12:27 -080087static void test_gif_data_dims(skiatest::Reporter* r, void* data, size_t size, int width,
88 int height) {
89 SkBitmap bm;
90 bool imageDecodeSuccess = decode_memory(data, size, &bm);
91 REPORTER_ASSERT(r, imageDecodeSuccess);
92 REPORTER_ASSERT(r, bm.width() == width);
93 REPORTER_ASSERT(r, bm.height() == height);
94 REPORTER_ASSERT(r, !(bm.empty()));
95}
halcanary@google.com29d4e632013-10-11 18:21:56 +000096static void test_interlaced_gif_data(skiatest::Reporter* r,
97 void* data,
98 size_t size) {
99 SkBitmap bm;
msarett7f7ec202016-03-01 12:12:27 -0800100 bool imageDecodeSuccess = decode_memory(data, size, &bm);
halcanary@google.com29d4e632013-10-11 18:21:56 +0000101 REPORTER_ASSERT(r, imageDecodeSuccess);
102 REPORTER_ASSERT(r, bm.width() == 9);
103 REPORTER_ASSERT(r, bm.height() == 9);
104 REPORTER_ASSERT(r, !(bm.empty()));
105 if (!(bm.empty())) {
106 REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
107 REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
108 REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
109
110 REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
111 REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
112 REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
113
114 REPORTER_ASSERT(r, bm.getColor(0, 4) == 0xff808080);
115 REPORTER_ASSERT(r, bm.getColor(1, 4) == 0xff000000);
116 REPORTER_ASSERT(r, bm.getColor(2, 4) == 0xff00ff00);
117
118 REPORTER_ASSERT(r, bm.getColor(0, 6) == 0xffff0000);
119 REPORTER_ASSERT(r, bm.getColor(1, 6) == 0xffffff00);
120 REPORTER_ASSERT(r, bm.getColor(2, 6) == 0xff00ffff);
121
122 REPORTER_ASSERT(r, bm.getColor(0, 8) == 0xffffffff);
123 REPORTER_ASSERT(r, bm.getColor(1, 8) == 0xffff00ff);
124 REPORTER_ASSERT(r, bm.getColor(2, 8) == 0xff0000ff);
125 }
126}
127
128static void test_gif_data_short(skiatest::Reporter* r,
129 void* data,
130 size_t size) {
131 SkBitmap bm;
msarett7f7ec202016-03-01 12:12:27 -0800132 bool imageDecodeSuccess = decode_memory(data, size, &bm);
halcanary@google.com29d4e632013-10-11 18:21:56 +0000133 REPORTER_ASSERT(r, imageDecodeSuccess);
134 REPORTER_ASSERT(r, bm.width() == 3);
135 REPORTER_ASSERT(r, bm.height() == 3);
136 REPORTER_ASSERT(r, !(bm.empty()));
137 if (!(bm.empty())) {
138 REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
139 REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
140 REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
141 REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
142 REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
143 REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
144 }
145}
146
147/**
msarett7f7ec202016-03-01 12:12:27 -0800148 This test will test the ability of the SkCodec to deal with
halcanary@google.com29d4e632013-10-11 18:21:56 +0000149 GIF files which have been mangled somehow. We want to display as
150 much of the GIF as possible.
151*/
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000152DEF_TEST(Gif, reporter) {
halcanary@google.com29d4e632013-10-11 18:21:56 +0000153 // test perfectly good images.
tfarina@chromium.org58674812014-01-21 23:39:22 +0000154 test_gif_data(reporter, static_cast<void *>(gGIFData), sizeof(gGIFData));
155 test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
156 sizeof(gInterlacedGIF));
halcanary@google.com29d4e632013-10-11 18:21:56 +0000157
tfarina@chromium.org58674812014-01-21 23:39:22 +0000158 unsigned char badData[sizeof(gGIFData)];
halcanary@google.com29d4e632013-10-11 18:21:56 +0000159
tfarina@chromium.org58674812014-01-21 23:39:22 +0000160 memcpy(badData, gGIFData, sizeof(gGIFData));
halcanary@google.com29d4e632013-10-11 18:21:56 +0000161 badData[6] = 0x01; // image too wide
tfarina@chromium.org58674812014-01-21 23:39:22 +0000162 test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
halcanary@google.com29d4e632013-10-11 18:21:56 +0000163 // "libgif warning [image too wide, expanding output to size]"
164
tfarina@chromium.org58674812014-01-21 23:39:22 +0000165 memcpy(badData, gGIFData, sizeof(gGIFData));
halcanary@google.com29d4e632013-10-11 18:21:56 +0000166 badData[8] = 0x01; // image too tall
tfarina@chromium.org58674812014-01-21 23:39:22 +0000167 test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
halcanary@google.com29d4e632013-10-11 18:21:56 +0000168 // "libgif warning [image too tall, expanding output to size]"
169
tfarina@chromium.org58674812014-01-21 23:39:22 +0000170 memcpy(badData, gGIFData, sizeof(gGIFData));
halcanary@google.com29d4e632013-10-11 18:21:56 +0000171 badData[62] = 0x01; // image shifted right
msarett7f7ec202016-03-01 12:12:27 -0800172 test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 4, 3);
halcanary@google.com29d4e632013-10-11 18:21:56 +0000173
tfarina@chromium.org58674812014-01-21 23:39:22 +0000174 memcpy(badData, gGIFData, sizeof(gGIFData));
halcanary@google.com29d4e632013-10-11 18:21:56 +0000175 badData[64] = 0x01; // image shifted down
msarett7f7ec202016-03-01 12:12:27 -0800176 test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 4);
halcanary@google.com29d4e632013-10-11 18:21:56 +0000177
tfarina@chromium.org58674812014-01-21 23:39:22 +0000178 memcpy(badData, gGIFData, sizeof(gGIFData));
msarett7f7ec202016-03-01 12:12:27 -0800179 badData[62] = 0xff; // image shifted right
180 badData[63] = 0xff;
181 test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3 + 0xFFFF, 3);
halcanary@google.com29d4e632013-10-11 18:21:56 +0000182
tfarina@chromium.org58674812014-01-21 23:39:22 +0000183 memcpy(badData, gGIFData, sizeof(gGIFData));
msarett7f7ec202016-03-01 12:12:27 -0800184 badData[64] = 0xff; // image shifted down
185 badData[65] = 0xff;
186 test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 3 + 0xFFFF);
halcanary@google.com29d4e632013-10-11 18:21:56 +0000187
tfarina@chromium.org58674812014-01-21 23:39:22 +0000188 test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap),
189 sizeof(gGIFDataNoColormap));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500190
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400191#ifdef SK_HAS_WUFFS_LIBRARY
192 // We are transitioning from an old GIF implementation to a new (Wuffs) GIF
193 // implementation.
194 //
195 // This test (without SK_HAS_WUFFS_LIBRARY) is overly specific to the old
196 // implementation. It claims that, for invalid (truncated) input, we can
197 // still 'decode' all of the pixels because no matter what palette index
198 // each pixel is, they're all equivalently transparent. It's not obvious
199 // that this off-spec behavior is worth preserving. Are real world users
200 // decoding truncated all-transparent GIF images??
201 //
202 // Once the transition is complete, we can remove the #ifdef and delete the
203 // #else branch.
204#else
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500205 // Since there is no color map, we do not even need to parse the image data
206 // to know that we should draw transparent. Truncate the file before the
207 // data. This should still succeed.
208 test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap), 31);
209
210 // Likewise, incremental decoding should succeed here.
211 {
212 sk_sp<SkData> data = SkData::MakeWithoutCopy(gGIFDataNoColormap, 31);
Mike Reedede7bac2017-07-23 15:30:02 -0400213 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
Leon Scroggins III3fc97d72016-12-09 16:39:33 -0500214 REPORTER_ASSERT(reporter, codec);
215 if (codec) {
216 auto info = codec->getInfo().makeColorType(kN32_SkColorType);
217 SkBitmap bm;
218 bm.allocPixels(info);
219 REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->startIncrementalDecode(
220 info, bm.getPixels(), bm.rowBytes()));
221 REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->incrementalDecode());
222 REPORTER_ASSERT(reporter, bm.width() == 1);
223 REPORTER_ASSERT(reporter, bm.height() == 1);
224 REPORTER_ASSERT(reporter, !(bm.empty()));
225 if (!(bm.empty())) {
226 REPORTER_ASSERT(reporter, bm.getColor(0, 0) == 0x00000000);
227 }
228 }
229 }
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400230#endif
halcanary@google.com29d4e632013-10-11 18:21:56 +0000231
232 // test short Gif. 80 is missing a few bytes.
tfarina@chromium.org58674812014-01-21 23:39:22 +0000233 test_gif_data_short(reporter, static_cast<void *>(gGIFData), 80);
halcanary@google.com29d4e632013-10-11 18:21:56 +0000234 // "libgif warning [DGifGetLine]"
235
tfarina@chromium.org58674812014-01-21 23:39:22 +0000236 test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
halcanary@google.com29d4e632013-10-11 18:21:56 +0000237 100); // 100 is missing a few bytes
238 // "libgif warning [interlace DGifGetLine]"
239}
240
scroggo9d214292015-05-14 14:44:13 -0700241// Regression test for decoding a gif image with sampleSize of 4, which was
242// previously crashing.
243DEF_TEST(Gif_Sampled, r) {
Mike Reed0933bc92017-12-09 01:27:41 +0000244 auto data = GetResourceAsData("images/test640x479.gif");
245 REPORTER_ASSERT(r, data);
246 if (!data) {
scroggo9d214292015-05-14 14:44:13 -0700247 return;
248 }
Mike Reed0933bc92017-12-09 01:27:41 +0000249 std::unique_ptr<SkStreamAsset> stream(new SkMemoryStream(std::move(data)));
Mike Reedede7bac2017-07-23 15:30:02 -0400250 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(std::move(stream)));
msarett7f7ec202016-03-01 12:12:27 -0800251 REPORTER_ASSERT(r, codec);
252 if (!codec) {
scroggo9d214292015-05-14 14:44:13 -0700253 return;
254 }
msarett7f7ec202016-03-01 12:12:27 -0800255
msarett7f7ec202016-03-01 12:12:27 -0800256 SkAndroidCodec::AndroidOptions options;
257 options.fSampleSize = 4;
msarett7f7ec202016-03-01 12:12:27 -0800258
scroggo9d214292015-05-14 14:44:13 -0700259 SkBitmap bm;
Leon Scroggins571b30f2017-07-11 17:35:31 +0000260 bm.allocPixels(codec->getInfo());
msarett7f7ec202016-03-01 12:12:27 -0800261 const SkCodec::Result result = codec->getAndroidPixels(codec->getInfo(), bm.getPixels(),
262 bm.rowBytes(), &options);
263 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
scroggo9d214292015-05-14 14:44:13 -0700264}
Leon Scroggins III4993b952016-12-08 11:54:04 -0500265
266// If a GIF file is truncated before the header for the first image is defined,
267// we should not create an SkCodec.
268DEF_TEST(Codec_GifTruncated, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500269 sk_sp<SkData> data(GetResourceAsData("images/test640x479.gif"));
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400270 if (!data) {
271 return;
272 }
Leon Scroggins III4993b952016-12-08 11:54:04 -0500273
274 // This is right before the header for the first image.
275 data = SkData::MakeSubset(data.get(), 0, 446);
Mike Reedede7bac2017-07-23 15:30:02 -0400276 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
Leon Scroggins III4993b952016-12-08 11:54:04 -0500277 REPORTER_ASSERT(r, !codec);
278}
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400279
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400280/*
281For the Codec_GifTruncated2 test, immediately below,
282resources/images/box.gif's first 23 bytes are:
283
28400000000: 4749 4638 3961 c800 3700 203f 002c 0000 GIF89a..7. ?.,..
28500000010: 0000 c800 3700 85 ....7..
286
287The breakdown:
288
289@000 6 bytes magic "GIF89a"
290@006 7 bytes Logical Screen Descriptor: 0xC8 0x00 ... 0x00
291 - width = 200
292 - height = 55
293 - flags = 0x20
294 - background color index, pixel aspect ratio bytes ignored
295@00D 10 bytes Image Descriptor header: 0x2C 0x00 ... 0x85
296 - origin_x = 0
297 - origin_y = 0
298 - width = 200
299 - height = 55
300 - flags = 0x85, local color table, 64 RGB entries
301
302In particular, 23 bytes is after the header, but before the color table.
303*/
304
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400305DEF_TEST(Codec_GifTruncated2, r) {
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400306 // Truncate box.gif at 21, 22 and 23 bytes.
307 //
308 // See also Codec_GifTruncated3 in this file, below.
309 //
310 // See also Codec_trunc in CodecAnimTest.cpp for this magic 23.
311 //
312 // See also Codec_GifPreMap in CodecPartialTest.cpp for this magic 23.
313 for (int i = 21; i < 24; i++) {
314 sk_sp<SkData> data(GetResourceAsData("images/box.gif"));
315 if (!data) {
316 return;
317 }
318
319 data = SkData::MakeSubset(data.get(), 0, i);
320 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
321
322 if (i <= 21) {
323 if (codec) {
324 ERRORF(r, "Invalid data gave non-nullptr codec");
325 }
326 return;
327 }
328
329 if (!codec) {
330 ERRORF(r, "Failed to create codec with partial data (truncated at %d)", i);
331 return;
332 }
333
334#ifdef SK_HAS_WUFFS_LIBRARY
335 // We are transitioning from an old GIF implementation to a new (Wuffs)
336 // GIF implementation.
337 //
338 // The input is truncated in the Image Descriptor, before the local
339 // color table, and before (21) or after (22, 23) the first frame's
340 // XYWH (left / top / width / height) can be decoded. A detailed
341 // breakdown of those 23 bytes is in a comment above this function.
342 //
343 // With the old implementation, this test claimed that "no frame is
344 // complete enough that it has its metadata". In terms of the
345 // underlying file format, this claim is true for truncating at 21
346 // bytes, but not true for 22 or 23.
347 //
348 // At 21 bytes, both the old and new implementation's MakeFromStream
349 // factory method returns a nullptr SkCodec*, because creating a
350 // SkCodec requires knowing the image width and height (as its
351 // constructor takes an SkEncodedInfo argument), and specifically for
352 // GIF, decoding the image width and height requires decoding the first
353 // frame's XYWH, as per
354 // https://raw.githubusercontent.com/google/wuffs/master/test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt
355 //
356 // At 22 or 23 bytes, the first frame is complete enough that we can
357 // fill in all of a SkCodec::FrameInfo's fields (other than
358 // fFullyReceived). Specifically, we can fill in fRequiredFrame and
359 // fAlphaType, even though we haven't yet decoded the frame's RGB
360 // palette entries, as we do know the frame rectangle and that every
361 // palette entry is fully opaque, due to the lack of a Graphic Control
362 // Extension before the Image Descriptor.
363 //
364 // The new implementation correctly reports that the first frame's
365 // metadata is complete enough. The old implementation does not.
366 //
367 // Once the transition is complete, we can remove the #ifdef and delete
368 // the #else code.
369 REPORTER_ASSERT(r, codec->getFrameCount() == 1);
370#else
371 // The old implementation claimed:
372 //
373 // Although we correctly created a codec, no frame is
374 // complete enough that it has its metadata. Returning 0
375 // ensures that Chromium will not try to create a frame
376 // too early.
377 REPORTER_ASSERT(r, codec->getFrameCount() == 0);
378#endif
379 }
380}
381
382#ifdef SK_HAS_WUFFS_LIBRARY
383// This tests that, after truncating the input, the pixels are still
384// zero-initialized. If you comment out the SkSampler::Fill call in
385// SkWuffsCodec::onStartIncrementalDecode, the test could still pass (in a
386// standard configuration) but should fail with the MSAN memory sanitizer.
387DEF_TEST(Codec_GifTruncated3, r) {
Hal Canaryc465d132017-12-08 10:21:31 -0500388 sk_sp<SkData> data(GetResourceAsData("images/box.gif"));
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400389 if (!data) {
390 return;
391 }
392
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400393 data = SkData::MakeSubset(data.get(), 0, 23);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400394 sk_sp<SkImage> image(SkImage::MakeFromEncoded(data));
395
396 if (!image) {
397 ERRORF(r, "Missing image");
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400398 return;
399 }
400
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400401 REPORTER_ASSERT(r, image->width() == 200);
402 REPORTER_ASSERT(r, image->height() == 55);
403
404 SkBitmap bm;
405 if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(200, 55))) {
406 ERRORF(r, "Failed to allocate pixels");
407 return;
408 }
409
410 bm.eraseColor(SK_ColorTRANSPARENT);
411
412 SkCanvas canvas(bm);
413 canvas.drawImage(image, 0, 0, nullptr);
414
415 for (int i = 0; i < image->width(); ++i)
416 for (int j = 0; j < image->height(); ++j) {
417 SkColor actual = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(i, j));
418 if (actual != SK_ColorTRANSPARENT) {
419 ERRORF(r, "did not initialize pixels! %i, %i is %x", i, j, actual);
420 }
421 }
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400422}
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400423#endif
Leon Scroggins IIIf05626b2018-10-11 13:50:28 -0400424
425DEF_TEST(Codec_gif_out_of_palette, r) {
426 if (GetResourcePath().isEmpty()) {
427 return;
428 }
429
430 const char* path = "images/out-of-palette.gif";
431 auto data = GetResourceAsData(path);
432 if (!data) {
433 ERRORF(r, "failed to find %s", path);
434 return;
435 }
436
437 auto codec = SkCodec::MakeFromData(std::move(data));
438 if (!codec) {
439 ERRORF(r, "Could not create codec from %s", path);
440 return;
441 }
442
443 SkBitmap bm;
444 bm.allocPixels(codec->getInfo());
445 auto result = codec->getPixels(bm.pixmap());
446 REPORTER_ASSERT(r, result == SkCodec::kSuccess, "Failed to decode %s with error %s",
447 path, SkCodec::ResultToString(result));
448
449 struct {
450 int x;
451 int y;
452 SkColor expected;
453 } pixels[] = {
454 { 0, 0, SK_ColorBLACK },
455 { 1, 0, SK_ColorWHITE },
456 { 0, 1, SK_ColorTRANSPARENT },
457 { 1, 1, SK_ColorTRANSPARENT },
458 };
459 for (auto& pixel : pixels) {
460 auto actual = bm.getColor(pixel.x, pixel.y);
461 REPORTER_ASSERT(r, actual == pixel.expected,
462 "pixel (%i,%i) mismatch! expected: %x actual: %x",
463 pixel.x, pixel.y, pixel.expected, actual);
464 }
465}