1 /*
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 
8 #include "CodecPriv.h"
9 #include "Resources.h"
10 #include "SkAndroidCodec.h"
11 #include "SkBitmap.h"
12 #include "SkData.h"
13 #include "SkImage.h"
14 #include "SkStream.h"
15 #include "SkTypes.h"
16 #include "Test.h"
17 
18 static unsigned char gGIFData[] = {
19   0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x03, 0x00, 0x03, 0x00, 0xe3, 0x08,
20   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00,
21   0xff, 0x80, 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
22   0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
24   0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x04,
25   0x07, 0x50, 0x1c, 0x43, 0x40, 0x41, 0x23, 0x44, 0x00, 0x3b
26 };
27 
28 static unsigned char gGIFDataNoColormap[] = {
29   // Header
30   0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
31   // Screen descriptor
32   0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
33   // Graphics control extension
34   0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00, 0x01, 0x00,
35   // Image descriptor
36   0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
37   // Image data
38   0x02, 0x02, 0x4c, 0x01, 0x00,
39   // Trailer
40   0x3b
41 };
42 
43 static unsigned char gInterlacedGIF[] = {
44   0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x09, 0x00, 0x09, 0x00, 0xe3, 0x08, 0x00,
45   0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80,
46   0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
47   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
48   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00,
49   0x00, 0x09, 0x00, 0x09, 0x00, 0x40, 0x04, 0x1b, 0x50, 0x1c, 0x23, 0xe9, 0x44,
50   0x23, 0x60, 0x9d, 0x09, 0x28, 0x1e, 0xf8, 0x6d, 0x64, 0x56, 0x9d, 0x53, 0xa8,
51   0x7e, 0xa8, 0x65, 0x94, 0x5c, 0xb0, 0x8a, 0x45, 0x04, 0x00, 0x3b
52 };
53 
54 static void test_gif_data_no_colormap(skiatest::Reporter* r,
55                                       void* data,
56                                       size_t size) {
57     SkBitmap bm;
58     bool imageDecodeSuccess = decode_memory(data, size, &bm);
59     REPORTER_ASSERT(r, imageDecodeSuccess);
60     REPORTER_ASSERT(r, bm.width() == 1);
61     REPORTER_ASSERT(r, bm.height() == 1);
62     REPORTER_ASSERT(r, !(bm.empty()));
63     if (!(bm.empty())) {
64         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0x00000000);
65     }
66 }
67 static void test_gif_data(skiatest::Reporter* r, void* data, size_t size) {
68     SkBitmap bm;
69     bool imageDecodeSuccess = decode_memory(data, size, &bm);
70     REPORTER_ASSERT(r, imageDecodeSuccess);
71     REPORTER_ASSERT(r, bm.width() == 3);
72     REPORTER_ASSERT(r, bm.height() == 3);
73     REPORTER_ASSERT(r, !(bm.empty()));
74     if (!(bm.empty())) {
75         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
76         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
77         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
78         REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
79         REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
80         REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
81         REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
82         REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
83         REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
84     }
85 }
86 static void test_gif_data_dims(skiatest::Reporter* r, void* data, size_t size, int width,
87         int height) {
88     SkBitmap bm;
89     bool imageDecodeSuccess = decode_memory(data, size, &bm);
90     REPORTER_ASSERT(r, imageDecodeSuccess);
91     REPORTER_ASSERT(r, bm.width() == width);
92     REPORTER_ASSERT(r, bm.height() == height);
93     REPORTER_ASSERT(r, !(bm.empty()));
94 }
95 static void test_interlaced_gif_data(skiatest::Reporter* r,
96                                      void* data,
97                                      size_t size) {
98     SkBitmap bm;
99     bool imageDecodeSuccess = decode_memory(data, size, &bm);
100     REPORTER_ASSERT(r, imageDecodeSuccess);
101     REPORTER_ASSERT(r, bm.width() == 9);
102     REPORTER_ASSERT(r, bm.height() == 9);
103     REPORTER_ASSERT(r, !(bm.empty()));
104     if (!(bm.empty())) {
105         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
106         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
107         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
108 
109         REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
110         REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
111         REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
112 
113         REPORTER_ASSERT(r, bm.getColor(0, 4) == 0xff808080);
114         REPORTER_ASSERT(r, bm.getColor(1, 4) == 0xff000000);
115         REPORTER_ASSERT(r, bm.getColor(2, 4) == 0xff00ff00);
116 
117         REPORTER_ASSERT(r, bm.getColor(0, 6) == 0xffff0000);
118         REPORTER_ASSERT(r, bm.getColor(1, 6) == 0xffffff00);
119         REPORTER_ASSERT(r, bm.getColor(2, 6) == 0xff00ffff);
120 
121         REPORTER_ASSERT(r, bm.getColor(0, 8) == 0xffffffff);
122         REPORTER_ASSERT(r, bm.getColor(1, 8) == 0xffff00ff);
123         REPORTER_ASSERT(r, bm.getColor(2, 8) == 0xff0000ff);
124     }
125 }
126 
127 static void test_gif_data_short(skiatest::Reporter* r,
128                                 void* data,
129                                 size_t size) {
130     SkBitmap bm;
131     bool imageDecodeSuccess = decode_memory(data, size, &bm);
132     REPORTER_ASSERT(r, imageDecodeSuccess);
133     REPORTER_ASSERT(r, bm.width() == 3);
134     REPORTER_ASSERT(r, bm.height() == 3);
135     REPORTER_ASSERT(r, !(bm.empty()));
136     if (!(bm.empty())) {
137         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
138         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
139         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
140         REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
141         REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
142         REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
143     }
144 }
145 
146 /**
147   This test will test the ability of the SkCodec to deal with
148   GIF files which have been mangled somehow.  We want to display as
149   much of the GIF as possible.
150 */
151 DEF_TEST(Gif, reporter) {
152     // test perfectly good images.
153     test_gif_data(reporter, static_cast<void *>(gGIFData), sizeof(gGIFData));
154     test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
155                           sizeof(gInterlacedGIF));
156 
157     unsigned char badData[sizeof(gGIFData)];
158 
159     memcpy(badData, gGIFData, sizeof(gGIFData));
160     badData[6] = 0x01;  // image too wide
161     test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
162     // "libgif warning [image too wide, expanding output to size]"
163 
164     memcpy(badData, gGIFData, sizeof(gGIFData));
165     badData[8] = 0x01;  // image too tall
166     test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
167     // "libgif warning [image too tall,  expanding output to size]"
168 
169     memcpy(badData, gGIFData, sizeof(gGIFData));
170     badData[62] = 0x01;  // image shifted right
171     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 4, 3);
172 
173     memcpy(badData, gGIFData, sizeof(gGIFData));
174     badData[64] = 0x01;  // image shifted down
175     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 4);
176 
177     memcpy(badData, gGIFData, sizeof(gGIFData));
178     badData[62] = 0xff;  // image shifted right
179     badData[63] = 0xff;
180     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3 + 0xFFFF, 3);
181 
182     memcpy(badData, gGIFData, sizeof(gGIFData));
183     badData[64] = 0xff;  // image shifted down
184     badData[65] = 0xff;
185     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 3 + 0xFFFF);
186 
187     test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap),
188                               sizeof(gGIFDataNoColormap));
189 
190     // Since there is no color map, we do not even need to parse the image data
191     // to know that we should draw transparent. Truncate the file before the
192     // data. This should still succeed.
193     test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap), 31);
194 
195     // Likewise, incremental decoding should succeed here.
196     {
197         sk_sp<SkData> data = SkData::MakeWithoutCopy(gGIFDataNoColormap, 31);
198         std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
199         REPORTER_ASSERT(reporter, codec);
200         if (codec) {
201             auto info = codec->getInfo().makeColorType(kN32_SkColorType);
202             SkBitmap bm;
203             bm.allocPixels(info);
204             REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->startIncrementalDecode(
205                     info, bm.getPixels(), bm.rowBytes()));
206             REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->incrementalDecode());
207             REPORTER_ASSERT(reporter, bm.width() == 1);
208             REPORTER_ASSERT(reporter, bm.height() == 1);
209             REPORTER_ASSERT(reporter, !(bm.empty()));
210             if (!(bm.empty())) {
211                 REPORTER_ASSERT(reporter, bm.getColor(0, 0) == 0x00000000);
212             }
213         }
214     }
215 
216     // test short Gif.  80 is missing a few bytes.
217     test_gif_data_short(reporter, static_cast<void *>(gGIFData), 80);
218     // "libgif warning [DGifGetLine]"
219 
220     test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
221                              100);  // 100 is missing a few bytes
222     // "libgif warning [interlace DGifGetLine]"
223 }
224 
225 // Regression test for decoding a gif image with sampleSize of 4, which was
226 // previously crashing.
227 DEF_TEST(Gif_Sampled, r) {
228     auto data = GetResourceAsData("images/test640x479.gif");
229     REPORTER_ASSERT(r, data);
230     if (!data) {
231         return;
232     }
233     std::unique_ptr<SkStreamAsset> stream(new SkMemoryStream(std::move(data)));
234     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(std::move(stream)));
235     REPORTER_ASSERT(r, codec);
236     if (!codec) {
237         return;
238     }
239 
240     SkAndroidCodec::AndroidOptions options;
241     options.fSampleSize = 4;
242 
243     SkBitmap bm;
244     bm.allocPixels(codec->getInfo());
245     const SkCodec::Result result = codec->getAndroidPixels(codec->getInfo(), bm.getPixels(),
246             bm.rowBytes(), &options);
247     REPORTER_ASSERT(r, result == SkCodec::kSuccess);
248 }
249 
250 // If a GIF file is truncated before the header for the first image is defined,
251 // we should not create an SkCodec.
252 DEF_TEST(Codec_GifTruncated, r) {
253     sk_sp<SkData> data(GetResourceAsData("images/test640x479.gif"));
254     if (!data) {
255         return;
256     }
257 
258     // This is right before the header for the first image.
259     data = SkData::MakeSubset(data.get(), 0, 446);
260     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
261     REPORTER_ASSERT(r, !codec);
262 }
263 
264 DEF_TEST(Codec_GifTruncated2, r) {
265     sk_sp<SkData> data(GetResourceAsData("images/box.gif"));
266     if (!data) {
267         return;
268     }
269 
270     // This is after the header, but before the color table.
271     data = SkData::MakeSubset(data.get(), 0, 23);
272     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
273     if (!codec) {
274         ERRORF(r, "Failed to create codec with partial data");
275         return;
276     }
277 
278     // Although we correctly created a codec, no frame is
279     // complete enough that it has its metadata. Returning 0
280     // ensures that Chromium will not try to create a frame
281     // too early.
282     REPORTER_ASSERT(r, codec->getFrameCount() == 0);
283 }
284