Home | History | Annotate | Download | only in tests
      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::NewFromData(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     std::unique_ptr<SkFILEStream> stream(
    229             new SkFILEStream(GetResourcePath("test640x479.gif").c_str()));
    230     REPORTER_ASSERT(r, stream->isValid());
    231     if (!stream->isValid()) {
    232         return;
    233     }
    234 
    235     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.release()));
    236     REPORTER_ASSERT(r, codec);
    237     if (!codec) {
    238         return;
    239     }
    240 
    241     SkAndroidCodec::AndroidOptions options;
    242     options.fSampleSize = 4;
    243 
    244     SkBitmap bm;
    245     bm.allocPixels(codec->getInfo());
    246     const SkCodec::Result result = codec->getAndroidPixels(codec->getInfo(), bm.getPixels(),
    247             bm.rowBytes(), &options);
    248     REPORTER_ASSERT(r, result == SkCodec::kSuccess);
    249 }
    250 
    251 // If a GIF file is truncated before the header for the first image is defined,
    252 // we should not create an SkCodec.
    253 DEF_TEST(Codec_GifTruncated, r) {
    254     sk_sp<SkData> data(GetResourceAsData("test640x479.gif"));
    255     if (!data) {
    256         return;
    257     }
    258 
    259     // This is right before the header for the first image.
    260     data = SkData::MakeSubset(data.get(), 0, 446);
    261     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
    262     REPORTER_ASSERT(r, !codec);
    263 }
    264 
    265 DEF_TEST(Codec_GifTruncated2, r) {
    266     sk_sp<SkData> data(GetResourceAsData("box.gif"));
    267     if (!data) {
    268         return;
    269     }
    270 
    271     // This is after the header, but before the color table.
    272     data = SkData::MakeSubset(data.get(), 0, 23);
    273     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
    274     if (!codec) {
    275         ERRORF(r, "Failed to create codec with partial data");
    276         return;
    277     }
    278 
    279     // Although we correctly created a codec, no frame is
    280     // complete enough that it has its metadata. Returning 0
    281     // ensures that Chromium will not try to create a frame
    282     // too early.
    283     REPORTER_ASSERT(r, codec->getFrameCount() == 0);
    284 }
    285