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// This tests out GIF decoder (SkImageDecoder_libgif.cpp)
9// It is not used on these platforms:
10#if (!defined(SK_BUILD_FOR_WIN32)) &&           \
11    (!defined(SK_BUILD_FOR_IOS)) &&             \
12    (!defined(SK_BUILD_FOR_MAC))
13
14#include "SkBitmap.h"
15#include "SkData.h"
16#include "SkForceLinking.h"
17#include "SkImage.h"
18#include "SkImageDecoder.h"
19#include "SkStream.h"
20#include "Test.h"
21
22__SK_FORCE_IMAGE_DECODER_LINKING;
23
24static unsigned char gGIFData[] = {
25  0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x03, 0x00, 0x03, 0x00, 0xe3, 0x08,
26  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00,
27  0xff, 0x80, 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
28  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
29  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
30  0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x04,
31  0x07, 0x50, 0x1c, 0x43, 0x40, 0x41, 0x23, 0x44, 0x00, 0x3b
32};
33
34static unsigned char gGIFDataNoColormap[] = {
35  0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
36  0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
37  0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c, 0x01, 0x00, 0x3b
38};
39
40static unsigned char gInterlacedGIF[] = {
41  0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x09, 0x00, 0x09, 0x00, 0xe3, 0x08, 0x00,
42  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80,
43  0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
44  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00,
46  0x00, 0x09, 0x00, 0x09, 0x00, 0x40, 0x04, 0x1b, 0x50, 0x1c, 0x23, 0xe9, 0x44,
47  0x23, 0x60, 0x9d, 0x09, 0x28, 0x1e, 0xf8, 0x6d, 0x64, 0x56, 0x9d, 0x53, 0xa8,
48  0x7e, 0xa8, 0x65, 0x94, 0x5c, 0xb0, 0x8a, 0x45, 0x04, 0x00, 0x3b
49};
50
51static void test_gif_data_no_colormap(skiatest::Reporter* r,
52                                      void* data,
53                                      size_t size) {
54    SkBitmap bm;
55    bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
56        data, size, &bm);
57    REPORTER_ASSERT(r, imageDecodeSuccess);
58    REPORTER_ASSERT(r, bm.width() == 1);
59    REPORTER_ASSERT(r, bm.height() == 1);
60    REPORTER_ASSERT(r, !(bm.empty()));
61    if (!(bm.empty())) {
62        REPORTER_ASSERT(r, bm.getColor(0, 0) == 0x00000000);
63    }
64}
65static void test_gif_data(skiatest::Reporter* r, void* data, size_t size) {
66    SkBitmap bm;
67    bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
68        data, size, &bm);
69    REPORTER_ASSERT(r, imageDecodeSuccess);
70    REPORTER_ASSERT(r, bm.width() == 3);
71    REPORTER_ASSERT(r, bm.height() == 3);
72    REPORTER_ASSERT(r, !(bm.empty()));
73    if (!(bm.empty())) {
74        REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
75        REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
76        REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
77        REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
78        REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
79        REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
80        REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
81        REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
82        REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
83    }
84}
85static void test_interlaced_gif_data(skiatest::Reporter* r,
86                                     void* data,
87                                     size_t size) {
88    SkBitmap bm;
89    bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
90        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
118static void test_gif_data_short(skiatest::Reporter* r,
119                                void* data,
120                                size_t size) {
121    SkBitmap bm;
122    bool imageDecodeSuccess = SkImageDecoder::DecodeMemory(
123        data, size, &bm);
124    REPORTER_ASSERT(r, imageDecodeSuccess);
125    REPORTER_ASSERT(r, bm.width() == 3);
126    REPORTER_ASSERT(r, bm.height() == 3);
127    REPORTER_ASSERT(r, !(bm.empty()));
128    if (!(bm.empty())) {
129        REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
130        REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
131        REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
132        REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
133        REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
134        REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
135    }
136}
137
138/**
139  This test will test the ability of the SkImageDecoder to deal with
140  GIF files which have been mangled somehow.  We want to display as
141  much of the GIF as possible.
142*/
143DEF_TEST(Gif, reporter) {
144    // test perfectly good images.
145    test_gif_data(reporter, static_cast<void *>(gGIFData), sizeof(gGIFData));
146    test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
147                          sizeof(gInterlacedGIF));
148
149    unsigned char badData[sizeof(gGIFData)];
150
151    /* If you set the environment variable
152       skia_images_gif_suppressDecoderWarnings to 'false', you will
153       see warnings on stderr.  This is a feature.  */
154
155    memcpy(badData, gGIFData, sizeof(gGIFData));
156    badData[6] = 0x01;  // image too wide
157    test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
158    // "libgif warning [image too wide, expanding output to size]"
159
160    memcpy(badData, gGIFData, sizeof(gGIFData));
161    badData[8] = 0x01;  // image too tall
162    test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
163    // "libgif warning [image too tall,  expanding output to size]"
164
165    memcpy(badData, gGIFData, sizeof(gGIFData));
166    badData[62] = 0x01;  // image shifted right
167    test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
168    // "libgif warning [shifting image left to fit]"
169
170    memcpy(badData, gGIFData, sizeof(gGIFData));
171    badData[64] = 0x01;  // image shifted down
172    test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
173    // "libgif warning [shifting image up to fit]"
174
175    memcpy(badData, gGIFData, sizeof(gGIFData));
176    badData[62] = 0xff;  // image shifted left
177    badData[63] = 0xff;  // 2's complement -1 short
178    test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
179    // "libgif warning [shifting image left to fit]"
180
181    memcpy(badData, gGIFData, sizeof(gGIFData));
182    badData[64] = 0xff;  // image shifted up
183    badData[65] = 0xff;  // 2's complement -1 short
184    test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
185    // "libgif warning [shifting image up to fit]"
186
187    test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap),
188                              sizeof(gGIFDataNoColormap));
189    // "libgif warning [missing colormap]"
190
191    // test short Gif.  80 is missing a few bytes.
192    test_gif_data_short(reporter, static_cast<void *>(gGIFData), 80);
193    // "libgif warning [DGifGetLine]"
194
195    test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
196                             100);  // 100 is missing a few bytes
197    // "libgif warning [interlace DGifGetLine]"
198}
199
200#endif  // !(SK_BUILD_FOR_WIN32||SK_BUILD_FOR_IOS||SK_BUILD_FOR_MAC)
201