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   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
30   0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
31   0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c, 0x01, 0x00, 0x3b
32 };
33 
34 static unsigned char gInterlacedGIF[] = {
35   0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x09, 0x00, 0x09, 0x00, 0xe3, 0x08, 0x00,
36   0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80,
37   0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
38   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00,
40   0x00, 0x09, 0x00, 0x09, 0x00, 0x40, 0x04, 0x1b, 0x50, 0x1c, 0x23, 0xe9, 0x44,
41   0x23, 0x60, 0x9d, 0x09, 0x28, 0x1e, 0xf8, 0x6d, 0x64, 0x56, 0x9d, 0x53, 0xa8,
42   0x7e, 0xa8, 0x65, 0x94, 0x5c, 0xb0, 0x8a, 0x45, 0x04, 0x00, 0x3b
43 };
44 
test_gif_data_no_colormap(skiatest::Reporter * r,void * data,size_t size)45 static void test_gif_data_no_colormap(skiatest::Reporter* r,
46                                       void* data,
47                                       size_t size) {
48     SkBitmap bm;
49     bool imageDecodeSuccess = decode_memory(data, size, &bm);
50     REPORTER_ASSERT(r, imageDecodeSuccess);
51     REPORTER_ASSERT(r, bm.width() == 1);
52     REPORTER_ASSERT(r, bm.height() == 1);
53     REPORTER_ASSERT(r, !(bm.empty()));
54     if (!(bm.empty())) {
55         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xFF000000);
56     }
57 }
test_gif_data(skiatest::Reporter * r,void * data,size_t size)58 static void test_gif_data(skiatest::Reporter* r, void* data, size_t size) {
59     SkBitmap bm;
60     bool imageDecodeSuccess = decode_memory(data, size, &bm);
61     REPORTER_ASSERT(r, imageDecodeSuccess);
62     REPORTER_ASSERT(r, bm.width() == 3);
63     REPORTER_ASSERT(r, bm.height() == 3);
64     REPORTER_ASSERT(r, !(bm.empty()));
65     if (!(bm.empty())) {
66         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
67         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
68         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
69         REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
70         REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
71         REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
72         REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
73         REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
74         REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
75     }
76 }
test_gif_data_dims(skiatest::Reporter * r,void * data,size_t size,int width,int height)77 static void test_gif_data_dims(skiatest::Reporter* r, void* data, size_t size, int width,
78         int height) {
79     SkBitmap bm;
80     bool imageDecodeSuccess = decode_memory(data, size, &bm);
81     REPORTER_ASSERT(r, imageDecodeSuccess);
82     REPORTER_ASSERT(r, bm.width() == width);
83     REPORTER_ASSERT(r, bm.height() == height);
84     REPORTER_ASSERT(r, !(bm.empty()));
85 }
test_interlaced_gif_data(skiatest::Reporter * r,void * data,size_t size)86 static void test_interlaced_gif_data(skiatest::Reporter* r,
87                                      void* data,
88                                      size_t size) {
89     SkBitmap bm;
90     bool imageDecodeSuccess = decode_memory(data, size, &bm);
91     REPORTER_ASSERT(r, imageDecodeSuccess);
92     REPORTER_ASSERT(r, bm.width() == 9);
93     REPORTER_ASSERT(r, bm.height() == 9);
94     REPORTER_ASSERT(r, !(bm.empty()));
95     if (!(bm.empty())) {
96         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
97         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
98         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
99 
100         REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
101         REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
102         REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
103 
104         REPORTER_ASSERT(r, bm.getColor(0, 4) == 0xff808080);
105         REPORTER_ASSERT(r, bm.getColor(1, 4) == 0xff000000);
106         REPORTER_ASSERT(r, bm.getColor(2, 4) == 0xff00ff00);
107 
108         REPORTER_ASSERT(r, bm.getColor(0, 6) == 0xffff0000);
109         REPORTER_ASSERT(r, bm.getColor(1, 6) == 0xffffff00);
110         REPORTER_ASSERT(r, bm.getColor(2, 6) == 0xff00ffff);
111 
112         REPORTER_ASSERT(r, bm.getColor(0, 8) == 0xffffffff);
113         REPORTER_ASSERT(r, bm.getColor(1, 8) == 0xffff00ff);
114         REPORTER_ASSERT(r, bm.getColor(2, 8) == 0xff0000ff);
115     }
116 }
117 
test_gif_data_short(skiatest::Reporter * r,void * data,size_t size)118 static void test_gif_data_short(skiatest::Reporter* r,
119                                 void* data,
120                                 size_t size) {
121     SkBitmap bm;
122     bool imageDecodeSuccess = decode_memory(data, size, &bm);
123     REPORTER_ASSERT(r, imageDecodeSuccess);
124     REPORTER_ASSERT(r, bm.width() == 3);
125     REPORTER_ASSERT(r, bm.height() == 3);
126     REPORTER_ASSERT(r, !(bm.empty()));
127     if (!(bm.empty())) {
128         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
129         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
130         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
131         REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
132         REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
133         REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
134     }
135 }
136 
137 /**
138   This test will test the ability of the SkCodec to deal with
139   GIF files which have been mangled somehow.  We want to display as
140   much of the GIF as possible.
141 */
DEF_TEST(Gif,reporter)142 DEF_TEST(Gif, reporter) {
143     // test perfectly good images.
144     test_gif_data(reporter, static_cast<void *>(gGIFData), sizeof(gGIFData));
145     test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
146                           sizeof(gInterlacedGIF));
147 
148     unsigned char badData[sizeof(gGIFData)];
149 
150     memcpy(badData, gGIFData, sizeof(gGIFData));
151     badData[6] = 0x01;  // image too wide
152     test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
153     // "libgif warning [image too wide, expanding output to size]"
154 
155     memcpy(badData, gGIFData, sizeof(gGIFData));
156     badData[8] = 0x01;  // image too tall
157     test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
158     // "libgif warning [image too tall,  expanding output to size]"
159 
160     memcpy(badData, gGIFData, sizeof(gGIFData));
161     badData[62] = 0x01;  // image shifted right
162     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 4, 3);
163 
164     memcpy(badData, gGIFData, sizeof(gGIFData));
165     badData[64] = 0x01;  // image shifted down
166     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 4);
167 
168     memcpy(badData, gGIFData, sizeof(gGIFData));
169     badData[62] = 0xff;  // image shifted right
170     badData[63] = 0xff;
171     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3 + 0xFFFF, 3);
172 
173     memcpy(badData, gGIFData, sizeof(gGIFData));
174     badData[64] = 0xff;  // image shifted down
175     badData[65] = 0xff;
176     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 3 + 0xFFFF);
177 
178     test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap),
179                               sizeof(gGIFDataNoColormap));
180     // "libgif warning [missing colormap]"
181 
182     // test short Gif.  80 is missing a few bytes.
183     test_gif_data_short(reporter, static_cast<void *>(gGIFData), 80);
184     // "libgif warning [DGifGetLine]"
185 
186     test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
187                              100);  // 100 is missing a few bytes
188     // "libgif warning [interlace DGifGetLine]"
189 }
190 
191 // Regression test for decoding a gif image with sampleSize of 4, which was
192 // previously crashing.
DEF_TEST(Gif_Sampled,r)193 DEF_TEST(Gif_Sampled, r) {
194     SkAutoTDelete<SkFILEStream> stream(
195             new SkFILEStream(GetResourcePath("test640x479.gif").c_str()));
196     REPORTER_ASSERT(r, stream->isValid());
197     if (!stream->isValid()) {
198         return;
199     }
200 
201     SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.detach()));
202     REPORTER_ASSERT(r, codec);
203     if (!codec) {
204         return;
205     }
206 
207     // Construct a color table for the decode if necessary
208     SkAutoTUnref<SkColorTable> colorTable(nullptr);
209     SkPMColor* colorPtr = nullptr;
210     int* colorCountPtr = nullptr;
211     int maxColors = 256;
212     if (kIndex_8_SkColorType == codec->getInfo().colorType()) {
213         SkPMColor colors[256];
214         colorTable.reset(new SkColorTable(colors, maxColors));
215         colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
216         colorCountPtr = &maxColors;
217     }
218 
219     SkAndroidCodec::AndroidOptions options;
220     options.fSampleSize = 4;
221     options.fColorPtr = colorPtr;
222     options.fColorCount = colorCountPtr;
223 
224     SkBitmap bm;
225     bm.allocPixels(codec->getInfo(), nullptr, colorTable.get());
226     const SkCodec::Result result = codec->getAndroidPixels(codec->getInfo(), bm.getPixels(),
227             bm.rowBytes(), &options);
228     REPORTER_ASSERT(r, result == SkCodec::kSuccess);
229 }
230