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 "Resources.h"
      9 #include "SkBitmap.h"
     10 #include "SkCanvas.h"
     11 #include "SkColor.h"
     12 #include "SkColorPriv.h"
     13 #include "SkData.h"
     14 #include "SkDecodingImageGenerator.h"
     15 #include "SkDiscardableMemoryPool.h"
     16 #include "SkForceLinking.h"
     17 #include "SkGradientShader.h"
     18 #include "SkImageDecoder.h"
     19 #include "SkImageEncoder.h"
     20 #include "SkImageGeneratorPriv.h"
     21 #include "SkImagePriv.h"
     22 #include "SkOSFile.h"
     23 #include "SkPoint.h"
     24 #include "SkShader.h"
     25 #include "SkStream.h"
     26 #include "SkString.h"
     27 #include "Test.h"
     28 
     29 __SK_FORCE_IMAGE_DECODER_LINKING;
     30 
     31 /**
     32  *  Interprets c as an unpremultiplied color, and returns the
     33  *  premultiplied equivalent.
     34  */
     35 static SkPMColor premultiply_unpmcolor(SkPMColor c) {
     36     U8CPU a = SkGetPackedA32(c);
     37     U8CPU r = SkGetPackedR32(c);
     38     U8CPU g = SkGetPackedG32(c);
     39     U8CPU b = SkGetPackedB32(c);
     40     return SkPreMultiplyARGB(a, r, g, b);
     41 }
     42 
     43 /**
     44  *  Return true if this stream format should be skipped, due
     45  *  to do being an opaque format or not a valid format.
     46  */
     47 static bool skip_image_format(SkImageDecoder::Format format) {
     48     switch (format) {
     49         case SkImageDecoder::kPNG_Format:
     50         case SkImageDecoder::kWEBP_Format:
     51             return false;
     52         // Skip unknown since it will not be decoded anyway.
     53         case SkImageDecoder::kUnknown_Format:
     54         // Technically ICO and BMP supports alpha channels, but our image
     55         // decoders do not, so skip them as well.
     56         case SkImageDecoder::kICO_Format:
     57         case SkImageDecoder::kBMP_Format:
     58         // KTX and ASTC are texture formats so it's not particularly clear how to
     59         // decode the alpha from them.
     60         case SkImageDecoder::kKTX_Format:
     61         case SkImageDecoder::kASTC_Format:
     62         // The rest of these are opaque.
     63         case SkImageDecoder::kPKM_Format:
     64         case SkImageDecoder::kWBMP_Format:
     65         case SkImageDecoder::kGIF_Format:
     66         case SkImageDecoder::kJPEG_Format:
     67             return true;
     68     }
     69     SkASSERT(false);
     70     return true;
     71 }
     72 
     73 /**
     74  *  Test decoding an image in premultiplied mode and unpremultiplied mode and compare
     75  *  them.
     76  */
     77 static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filename) {
     78     // Decode a resource:
     79     SkBitmap bm8888;
     80     SkBitmap bm8888Unpremul;
     81 
     82     SkFILEStream stream(filename.c_str());
     83 
     84     SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&stream);
     85     if (skip_image_format(format)) {
     86         return;
     87     }
     88 
     89     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
     90     if (NULL == decoder.get()) {
     91         SkDebugf("couldn't decode %s\n", filename.c_str());
     92         return;
     93     }
     94 
     95     bool success = decoder->decode(&stream, &bm8888, kN32_SkColorType,
     96                                    SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure;
     97     if (!success) {
     98         return;
     99     }
    100 
    101     success = stream.rewind();
    102     REPORTER_ASSERT(reporter, success);
    103     if (!success) {
    104         return;
    105     }
    106 
    107     decoder->setRequireUnpremultipliedColors(true);
    108     success = decoder->decode(&stream, &bm8888Unpremul, kN32_SkColorType,
    109                               SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure;
    110     if (!success) {
    111         return;
    112     }
    113 
    114     bool dimensionsMatch = bm8888.width() == bm8888Unpremul.width()
    115                            && bm8888.height() == bm8888Unpremul.height();
    116     REPORTER_ASSERT(reporter, dimensionsMatch);
    117     if (!dimensionsMatch) {
    118         return;
    119     }
    120 
    121     // Only do the comparison if the two bitmaps are both 8888.
    122     if (bm8888.colorType() != kN32_SkColorType || bm8888Unpremul.colorType() != kN32_SkColorType) {
    123         return;
    124     }
    125 
    126     // Now compare the two bitmaps.
    127     for (int i = 0; i < bm8888.width(); ++i) {
    128         for (int j = 0; j < bm8888.height(); ++j) {
    129             // "c0" is the color of the premultiplied bitmap at (i, j).
    130             const SkPMColor c0 = *bm8888.getAddr32(i, j);
    131             // "c1" is the result of premultiplying the color of the unpremultiplied
    132             // bitmap at (i, j).
    133             const SkPMColor c1 = premultiply_unpmcolor(*bm8888Unpremul.getAddr32(i, j));
    134             // Compute the difference for each component.
    135             int da = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
    136             int dr = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
    137             int dg = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
    138             int db = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
    139 
    140             // Alpha component must be exactly the same.
    141             REPORTER_ASSERT(reporter, 0 == da);
    142 
    143             // Color components may not match exactly due to rounding error.
    144             REPORTER_ASSERT(reporter, dr <= 1);
    145             REPORTER_ASSERT(reporter, dg <= 1);
    146             REPORTER_ASSERT(reporter, db <= 1);
    147         }
    148     }
    149 }
    150 
    151 static void test_unpremul(skiatest::Reporter* reporter) {
    152     // This test cannot run if there is no resource path.
    153     SkString resourcePath = GetResourcePath();
    154     if (resourcePath.isEmpty()) {
    155         SkDebugf("Could not run unpremul test because resourcePath not specified.");
    156         return;
    157     }
    158     SkOSFile::Iter iter(resourcePath.c_str());
    159     SkString basename;
    160     if (iter.next(&basename)) {
    161         do {
    162             SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
    163             // SkDebugf("about to decode \"%s\"\n", filename.c_str());
    164             compare_unpremul(reporter, filename);
    165         } while (iter.next(&basename));
    166     } else {
    167         SkDebugf("Failed to find any files :(\n");
    168     }
    169 }
    170 
    171 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
    172 // Test that the alpha type is what we expect.
    173 static void test_alphaType(skiatest::Reporter* reporter, const SkString& filename,
    174                            bool requireUnpremul) {
    175     SkBitmap bm;
    176     SkFILEStream stream(filename.c_str());
    177 
    178     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
    179     if (NULL == decoder.get()) {
    180         return;
    181     }
    182 
    183     decoder->setRequireUnpremultipliedColors(requireUnpremul);
    184 
    185     // Decode just the bounds. This should always succeed.
    186     bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
    187                                    SkImageDecoder::kDecodeBounds_Mode);
    188     REPORTER_ASSERT(reporter, success);
    189     if (!success) {
    190         return;
    191     }
    192 
    193     // Keep track of the alpha type for testing later. If the full decode
    194     // succeeds, the alpha type should be the same, unless the full decode
    195     // determined that the alpha type should actually be opaque, which may
    196     // not be known when only decoding the bounds.
    197     const SkAlphaType boundsAlphaType = bm.alphaType();
    198 
    199     // rewind should always succeed on SkFILEStream.
    200     success = stream.rewind();
    201     REPORTER_ASSERT(reporter, success);
    202     if (!success) {
    203         return;
    204     }
    205 
    206     success = decoder->decode(&stream, &bm, kN32_SkColorType, SkImageDecoder::kDecodePixels_Mode);
    207 
    208     if (!success) {
    209         // When the decoder is set to require unpremul, if it does not support
    210         // unpremul it will fail. This is the only reason the decode should
    211         // fail (since we know the files we are using to test can be decoded).
    212         REPORTER_ASSERT(reporter, requireUnpremul);
    213         return;
    214     }
    215 
    216     // The bounds decode should return with either the requested
    217     // premul/unpremul or opaque, if that value could be determined when only
    218     // decoding the bounds.
    219     if (requireUnpremul) {
    220         REPORTER_ASSERT(reporter, kUnpremul_SkAlphaType == boundsAlphaType
    221                                   || kOpaque_SkAlphaType == boundsAlphaType
    222                                   || filename.endsWith(".ico"));
    223         // TODO(halcanary): Find out why color_wheel.ico fails this test.
    224     } else {
    225         REPORTER_ASSERT(reporter, kPremul_SkAlphaType == boundsAlphaType
    226                                   || kOpaque_SkAlphaType == boundsAlphaType);
    227     }
    228 
    229     // When decoding the full image, the alpha type should match the one
    230     // returned by the bounds decode, unless the full decode determined that
    231     // the alpha type is actually opaque.
    232     REPORTER_ASSERT(reporter, bm.alphaType() == boundsAlphaType
    233                               || bm.alphaType() == kOpaque_SkAlphaType);
    234 }
    235 
    236 DEF_TEST(ImageDecoding_alphaType, reporter) {
    237     SkString resourcePath = GetResourcePath();
    238     if (resourcePath.isEmpty()) {
    239         SkDebugf("Could not run alphaType test because resourcePath not specified.");
    240         return;
    241     }
    242 
    243     SkOSFile::Iter iter(resourcePath.c_str());
    244     SkString basename;
    245     if (iter.next(&basename)) {
    246         do {
    247             SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
    248             for (int truth = 0; truth <= 1; ++truth) {
    249                 test_alphaType(reporter, filename, SkToBool(truth));
    250             }
    251         } while (iter.next(&basename));
    252     } else {
    253         SkDebugf("Failed to find any files :(\n");
    254     }
    255 
    256 }
    257 
    258 // Using known images, test that decoding into unpremul and premul behave as expected.
    259 DEF_TEST(ImageDecoding_unpremul, reporter) {
    260     SkString resourcePath = GetResourcePath();
    261     if (resourcePath.isEmpty()) {
    262         SkDebugf("Could not run unpremul test because resourcePath not specified.");
    263         return;
    264     }
    265     const char* root = "half-transparent-white-pixel";
    266     const char* suffixes[] = { ".png", ".webp" };
    267 
    268     for (size_t i = 0; i < SK_ARRAY_COUNT(suffixes); ++i) {
    269         SkString basename = SkStringPrintf("%s%s", root, suffixes[i]);
    270         SkString fullName = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
    271 
    272         SkBitmap bm;
    273         SkFILEStream stream(fullName.c_str());
    274 
    275         if (!stream.isValid()) {
    276             SkDebugf("file %s missing from resource directoy %s\n",
    277                      basename.c_str(), resourcePath.c_str());
    278             continue;
    279         }
    280 
    281         // This should never fail since we know the images we're decoding.
    282         SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
    283         REPORTER_ASSERT(reporter, decoder.get());
    284         if (NULL == decoder.get()) {
    285             continue;
    286         }
    287 
    288         // Test unpremultiplied. We know what color this should result in.
    289         decoder->setRequireUnpremultipliedColors(true);
    290         bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
    291                                        SkImageDecoder::kDecodePixels_Mode);
    292         REPORTER_ASSERT(reporter, success);
    293         if (!success) {
    294             continue;
    295         }
    296 
    297         REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
    298         {
    299             SkAutoLockPixels alp(bm);
    300             REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7fffffff);
    301         }
    302 
    303         success = stream.rewind();
    304         REPORTER_ASSERT(reporter, success);
    305         if (!success) {
    306             continue;
    307         }
    308 
    309         // Test premultiplied. Once again, we know which color this should
    310         // result in.
    311         decoder->setRequireUnpremultipliedColors(false);
    312         success = decoder->decode(&stream, &bm, kN32_SkColorType,
    313                                   SkImageDecoder::kDecodePixels_Mode);
    314         REPORTER_ASSERT(reporter, success);
    315         if (!success) {
    316             continue;
    317         }
    318 
    319         REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
    320         {
    321             SkAutoLockPixels alp(bm);
    322             REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7f7f7f7f);
    323         }
    324     }
    325 }
    326 #endif // SK_BUILD_FOR_UNIX/ANDROID skbug.com/2388
    327 
    328 #ifdef SK_DEBUG
    329 // Test inside SkScaledBitmapSampler.cpp
    330 extern void test_row_proc_choice();
    331 #endif  // SK_DEBUG
    332 
    333 DEF_TEST(ImageDecoding, reporter) {
    334     test_unpremul(reporter);
    335 #ifdef SK_DEBUG
    336     test_row_proc_choice();
    337 #endif
    338 }
    339 
    340 // expected output for 8x8 bitmap
    341 static const int kExpectedWidth = 8;
    342 static const int kExpectedHeight = 8;
    343 static const SkColor kExpectedPixels[] = {
    344     0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666,
    345     0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093,
    346     0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4,
    347     0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3,
    348     0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e,
    349     0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689,
    350     0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d,
    351     0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46,
    352     0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67,
    353     0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4,
    354     0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283,
    355     0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4,
    356     0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4,
    357     0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a,
    358     0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738,
    359     0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df
    360 };
    361 SK_COMPILE_ASSERT((kExpectedWidth * kExpectedHeight)
    362                   == SK_ARRAY_COUNT(kExpectedPixels), array_size_mismatch);
    363 
    364 DEF_TEST(WebP, reporter) {
    365     const unsigned char encodedWebP[] = {
    366         0x52, 0x49, 0x46, 0x46, 0x2c, 0x01, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
    367         0x56, 0x50, 0x38, 0x4c, 0x20, 0x01, 0x00, 0x00, 0x2f, 0x07, 0xc0, 0x01,
    368         0x00, 0xff, 0x01, 0x45, 0x03, 0x00, 0xe2, 0xd5, 0xae, 0x60, 0x2b, 0xad,
    369         0xd9, 0x68, 0x76, 0xb6, 0x8d, 0x6a, 0x1d, 0xc0, 0xe6, 0x19, 0xd6, 0x16,
    370         0xb7, 0xb4, 0xef, 0xcf, 0xc3, 0x15, 0x6c, 0xb3, 0xbd, 0x77, 0x0d, 0x85,
    371         0x6d, 0x1b, 0xa9, 0xb1, 0x2b, 0xdc, 0x3d, 0x83, 0xdb, 0x00, 0x00, 0xc8,
    372         0x26, 0xe5, 0x01, 0x99, 0x8a, 0xd5, 0xdd, 0xfc, 0x82, 0xcd, 0xcd, 0x9a,
    373         0x8c, 0x13, 0xcc, 0x1b, 0xba, 0xf5, 0x05, 0xdb, 0xee, 0x6a, 0xdb, 0x38,
    374         0x60, 0xfe, 0x43, 0x2c, 0xd4, 0x6a, 0x99, 0x4d, 0xc6, 0xc0, 0xd3, 0x28,
    375         0x1b, 0xc1, 0xb1, 0x17, 0x4e, 0x43, 0x0e, 0x3d, 0x27, 0xe9, 0xe4, 0x84,
    376         0x4f, 0x24, 0x62, 0x69, 0x85, 0x43, 0x8d, 0xc2, 0x04, 0x00, 0x07, 0x59,
    377         0x60, 0xfd, 0x8b, 0x4d, 0x60, 0x32, 0x72, 0xcf, 0x88, 0x0c, 0x2f, 0x2f,
    378         0xad, 0x62, 0xbd, 0x27, 0x09, 0x16, 0x70, 0x78, 0x6c, 0xd9, 0x82, 0xef,
    379         0x1a, 0xa2, 0xcc, 0xf0, 0xf1, 0x6f, 0xd8, 0x78, 0x2e, 0x39, 0xa1, 0xcf,
    380         0x14, 0x4b, 0x89, 0xb4, 0x1b, 0x48, 0x15, 0x7c, 0x48, 0x6f, 0x8c, 0x20,
    381         0xb7, 0x00, 0xcf, 0xfc, 0xdb, 0xd0, 0xe9, 0xe7, 0x42, 0x09, 0xa4, 0x03,
    382         0x40, 0xac, 0xda, 0x40, 0x01, 0x00, 0x5f, 0xa1, 0x3d, 0x64, 0xe1, 0xf4,
    383         0x03, 0x45, 0x29, 0xe0, 0xe2, 0x4a, 0xc3, 0xa2, 0xe8, 0xe0, 0x25, 0x12,
    384         0x74, 0xc6, 0xe8, 0xfb, 0x93, 0x4f, 0x9f, 0x5e, 0xc0, 0xa6, 0x91, 0x1b,
    385         0xa4, 0x24, 0x82, 0xc3, 0x61, 0x07, 0x4c, 0x49, 0x4f, 0x53, 0xae, 0x5f,
    386         0x5d, 0x39, 0x36, 0xc0, 0x5b, 0x57, 0x54, 0x60, 0x10, 0x00, 0x00, 0xd1,
    387         0x68, 0xb6, 0x6d, 0xdb, 0x36, 0x22, 0xfa, 0x1f, 0x35, 0x75, 0x22, 0xec,
    388         0x31, 0xbc, 0x5d, 0x8f, 0x87, 0x53, 0xa2, 0x05, 0x8c, 0x2f, 0xcd, 0xa8,
    389         0xa7, 0xf3, 0xa3, 0xbd, 0x83, 0x8b, 0x2a, 0xc8, 0x58, 0xf5, 0xac, 0x80,
    390         0xe3, 0xfe, 0x66, 0xa4, 0x7c, 0x1b, 0x6c, 0xd1, 0xa9, 0xd8, 0x14, 0xd0,
    391         0xc5, 0xb5, 0x39, 0x71, 0x97, 0x19, 0x19, 0x1b
    392     };
    393     SkAutoDataUnref encoded(SkData::NewWithCopy(encodedWebP,
    394                                                 sizeof(encodedWebP)));
    395     SkBitmap bm;
    396 
    397     bool success = SkInstallDiscardablePixelRef(encoded, &bm);
    398 
    399     REPORTER_ASSERT(reporter, success);
    400     if (!success) {
    401         return;
    402     }
    403     SkAutoLockPixels alp(bm);
    404 
    405     bool rightSize = ((kExpectedWidth == bm.width())
    406                       && (kExpectedHeight == bm.height()));
    407     REPORTER_ASSERT(reporter, rightSize);
    408     if (rightSize) {
    409         bool error = false;
    410         const SkColor* correctPixel = kExpectedPixels;
    411         for (int y = 0; y < bm.height(); ++y) {
    412             for (int x = 0; x < bm.width(); ++x) {
    413                 error |= (*correctPixel != bm.getColor(x, y));
    414                 ++correctPixel;
    415             }
    416         }
    417         REPORTER_ASSERT(reporter, !error);
    418     }
    419 }
    420 
    421 ////////////////////////////////////////////////////////////////////////////////
    422 
    423 // example of how Android will do this inside their BitmapFactory
    424 static SkPixelRef* install_pixel_ref(SkBitmap* bitmap,
    425                                      SkStreamRewindable* stream,
    426                                      int sampleSize, bool ditherImage) {
    427     SkASSERT(bitmap != NULL);
    428     SkASSERT(stream != NULL);
    429     SkASSERT(stream->rewind());
    430     SkColorType colorType = bitmap->colorType();
    431     SkDecodingImageGenerator::Options opts(sampleSize, ditherImage, colorType);
    432     if (SkInstallDiscardablePixelRef(
    433                 SkDecodingImageGenerator::Create(stream, opts), bitmap)) {
    434         return bitmap->pixelRef();
    435     }
    436     return NULL;
    437 }
    438 /**
    439  *  A test for the SkDecodingImageGenerator::Create and
    440  *  SkInstallDiscardablePixelRef functions.
    441  */
    442 DEF_TEST(ImprovedBitmapFactory, reporter) {
    443     SkString pngFilename = GetResourcePath("randPixels.png");
    444     SkAutoTDelete<SkStreamRewindable> stream(SkStream::NewFromFile(pngFilename.c_str()));
    445     if (sk_exists(pngFilename.c_str())) {
    446         SkBitmap bm;
    447         SkAssertResult(bm.setInfo(SkImageInfo::MakeN32Premul(1, 1)));
    448         REPORTER_ASSERT(reporter,
    449             install_pixel_ref(&bm, stream.detach(), 1, true));
    450         SkAutoLockPixels alp(bm);
    451         REPORTER_ASSERT(reporter, bm.getPixels());
    452     }
    453 }
    454 
    455 
    456 ////////////////////////////////////////////////////////////////////////////////
    457 
    458 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
    459 static inline bool check_rounding(int value, int dividend, int divisor) {
    460     // returns true if the value is greater than floor(dividend/divisor)
    461     // and less than SkNextPow2(ceil(dividend - divisor))
    462     return (((divisor * value) > (dividend - divisor))
    463             && value <= SkNextPow2(((dividend - 1) / divisor) + 1));
    464 }
    465 #endif  // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
    466 
    467 
    468 #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
    469     #define kBackwards_SkColorType kRGBA_8888_SkColorType
    470 #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
    471     #define kBackwards_SkColorType kBGRA_8888_SkColorType
    472 #else
    473     #error "SK_*32_SHFIT values must correspond to BGRA or RGBA byte order"
    474 #endif
    475 
    476 static inline const char* SkColorType_to_string(SkColorType colorType) {
    477     switch(colorType) {
    478         case kAlpha_8_SkColorType:   return "Alpha_8";
    479         case kRGB_565_SkColorType:   return "RGB_565";
    480         case kARGB_4444_SkColorType: return "ARGB_4444";
    481         case kN32_SkColorType:       return "N32";
    482         case kBackwards_SkColorType: return "Backwards";
    483         case kIndex_8_SkColorType:   return "Index_8";
    484         default:                     return "ERROR";
    485     }
    486 }
    487 
    488 static inline const char* options_colorType(
    489         const SkDecodingImageGenerator::Options& opts) {
    490     if (opts.fUseRequestedColorType) {
    491         return SkColorType_to_string(opts.fRequestedColorType);
    492     } else {
    493         return "(none)";
    494     }
    495 }
    496 
    497 static inline const char* yn(bool value) {
    498     if (value) {
    499         return "yes";
    500     } else {
    501         return "no";
    502     }
    503 }
    504 
    505 /**
    506  * Given either a SkStream or a SkData, try to decode the encoded
    507  * image using the specified options and report errors.
    508  */
    509 static void test_options(skiatest::Reporter* reporter,
    510                          const SkDecodingImageGenerator::Options& opts,
    511                          SkStreamRewindable* encodedStream,
    512                          SkData* encodedData,
    513                          bool useData,
    514                          const SkString& path) {
    515     SkBitmap bm;
    516     bool success = false;
    517     if (useData) {
    518         if (NULL == encodedData) {
    519             return;
    520         }
    521         success = SkInstallDiscardablePixelRef(
    522             SkDecodingImageGenerator::Create(encodedData, opts), &bm);
    523     } else {
    524         if (NULL == encodedStream) {
    525             return;
    526         }
    527         success = SkInstallDiscardablePixelRef(
    528             SkDecodingImageGenerator::Create(encodedStream->duplicate(), opts), &bm);
    529     }
    530     if (!success) {
    531         if (opts.fUseRequestedColorType
    532             && (kARGB_4444_SkColorType == opts.fRequestedColorType)) {
    533             return;  // Ignore known conversion inabilities.
    534         }
    535         // If we get here, it's a failure and we will need more
    536         // information about why it failed.
    537         ERRORF(reporter, "Bounds decode failed [sampleSize=%d dither=%s "
    538                "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
    539                options_colorType(opts), path.c_str());
    540         return;
    541     }
    542     #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
    543     // Android is the only system that use Skia's image decoders in
    544     // production.  For now, we'll only verify that samplesize works
    545     // on systems where it already is known to work.
    546     REPORTER_ASSERT(reporter, check_rounding(bm.height(), kExpectedHeight,
    547                                              opts.fSampleSize));
    548     REPORTER_ASSERT(reporter, check_rounding(bm.width(), kExpectedWidth,
    549                                              opts.fSampleSize));
    550     // The ImageDecoder API doesn't guarantee that SampleSize does
    551     // anything at all, but the decoders that this test excercises all
    552     // produce an output size in the following range:
    553     //    (((sample_size * out_size) > (in_size - sample_size))
    554     //     && out_size <= SkNextPow2(((in_size - 1) / sample_size) + 1));
    555     #endif  // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
    556     SkAutoLockPixels alp(bm);
    557     if (bm.getPixels() == NULL) {
    558         ERRORF(reporter, "Pixel decode failed [sampleSize=%d dither=%s "
    559                "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
    560                options_colorType(opts), path.c_str());
    561         return;
    562     }
    563 
    564     SkColorType requestedColorType = opts.fRequestedColorType;
    565     REPORTER_ASSERT(reporter,
    566                     (!opts.fUseRequestedColorType)
    567                     || (bm.colorType() == requestedColorType));
    568 
    569     // Condition under which we should check the decoding results:
    570     if ((kN32_SkColorType == bm.colorType())
    571         && (!path.endsWith(".jpg"))  // lossy
    572         && (opts.fSampleSize == 1)) {  // scaled
    573         const SkColor* correctPixels = kExpectedPixels;
    574         SkASSERT(bm.height() == kExpectedHeight);
    575         SkASSERT(bm.width() == kExpectedWidth);
    576         int pixelErrors = 0;
    577         for (int y = 0; y < bm.height(); ++y) {
    578             for (int x = 0; x < bm.width(); ++x) {
    579                 if (*correctPixels != bm.getColor(x, y)) {
    580                     ++pixelErrors;
    581                 }
    582                 ++correctPixels;
    583             }
    584         }
    585         if (pixelErrors != 0) {
    586             ERRORF(reporter, "Pixel-level mismatch (%d of %d) "
    587                    "[sampleSize=%d dither=%s colorType=%s %s]",
    588                    pixelErrors, kExpectedHeight * kExpectedWidth,
    589                    opts.fSampleSize, yn(opts.fDitherImage),
    590                    options_colorType(opts), path.c_str());
    591         }
    592     }
    593 }
    594 
    595 /**
    596  *  SkDecodingImageGenerator has an Options struct which lets the
    597  *  client of the generator set sample size, dithering, and bitmap
    598  *  config.  This test loops through many possible options and tries
    599  *  them on a set of 5 small encoded images (each in a different
    600  *  format).  We test both SkData and SkStreamRewindable decoding.
    601  */
    602 DEF_TEST(ImageDecoderOptions, reporter) {
    603     const char* files[]  = {
    604         "randPixels.bmp",
    605         "randPixels.jpg",
    606         "randPixels.png",
    607         "randPixels.webp",
    608         #if !defined(SK_BUILD_FOR_WIN)
    609         // TODO(halcanary): Find out why this fails sometimes.
    610         "randPixels.gif",
    611         #endif
    612     };
    613 
    614     SkString resourceDir = GetResourcePath();
    615     if (!sk_exists(resourceDir.c_str())) {
    616         return;
    617     }
    618 
    619     int scaleList[] = {1, 2, 3, 4};
    620     bool ditherList[] = {true, false};
    621     SkColorType colorList[] = {
    622         kAlpha_8_SkColorType,
    623         kRGB_565_SkColorType,
    624         kARGB_4444_SkColorType,  // Most decoders will fail on 4444.
    625         kN32_SkColorType
    626         // Note that indexed color is left out of the list.  Lazy
    627         // decoding doesn't do indexed color.
    628     };
    629     const bool useDataList[] = {true, false};
    630 
    631     for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) {
    632         SkString path = SkOSPath::Join(resourceDir.c_str(), files[fidx]);
    633         if (!sk_exists(path.c_str())) {
    634             continue;
    635         }
    636 
    637         SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str()));
    638         REPORTER_ASSERT(reporter, encodedData.get() != NULL);
    639         SkAutoTDelete<SkStreamRewindable> encodedStream(
    640             SkStream::NewFromFile(path.c_str()));
    641         REPORTER_ASSERT(reporter, encodedStream.get() != NULL);
    642 
    643         for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) {
    644             for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) {
    645                 for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) {
    646                     for (size_t k = 0; k < SK_ARRAY_COUNT(colorList); ++k) {
    647                         SkDecodingImageGenerator::Options opts(scaleList[i],
    648                                                                ditherList[j],
    649                                                                colorList[k]);
    650                         test_options(reporter, opts, encodedStream, encodedData,
    651                                      useDataList[m], path);
    652 
    653                     }
    654                     SkDecodingImageGenerator::Options options(scaleList[i],
    655                                                               ditherList[j]);
    656                     test_options(reporter, options, encodedStream, encodedData,
    657                                  useDataList[m], path);
    658                 }
    659             }
    660         }
    661     }
    662 }
    663 
    664 DEF_TEST(DiscardablePixelRef_SecondLockColorTableCheck, r) {
    665     SkString resourceDir = GetResourcePath();
    666     SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.gif");
    667     if (!sk_exists(path.c_str())) {
    668         return;
    669     }
    670     SkAutoDataUnref encoded(SkData::NewFromFileName(path.c_str()));
    671     SkBitmap bitmap;
    672     if (!SkInstallDiscardablePixelRef(
    673             SkDecodingImageGenerator::Create(
    674                     encoded, SkDecodingImageGenerator::Options()), &bitmap)) {
    675         #ifndef SK_BUILD_FOR_WIN
    676         ERRORF(r, "SkInstallDiscardablePixelRef [randPixels.gif] failed.");
    677         #endif
    678         return;
    679     }
    680     if (kIndex_8_SkColorType != bitmap.colorType()) {
    681         return;
    682     }
    683     {
    684         SkAutoLockPixels alp(bitmap);
    685         REPORTER_ASSERT(r, bitmap.getColorTable() && "first pass");
    686     }
    687     {
    688         SkAutoLockPixels alp(bitmap);
    689         REPORTER_ASSERT(r, bitmap.getColorTable() && "second pass");
    690     }
    691 }
    692 
    693 
    694 ////////////////////////////////////////////////////////////////////////////////
    695 namespace {
    696 class SingleAllocator : public SkBitmap::Allocator {
    697 public:
    698     SingleAllocator(void* p, size_t s) : fPixels(p), fSize(s) { }
    699     ~SingleAllocator() {}
    700     // If the pixels in fPixels are big enough, use them.
    701     bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) override {
    702         SkASSERT(bm);
    703         if (bm->info().getSafeSize(bm->rowBytes()) <= fSize) {
    704             bm->setPixels(fPixels, ct);
    705             fPixels = NULL;
    706             fSize = 0;
    707             return true;
    708         }
    709         return bm->tryAllocPixels(NULL, ct);
    710     }
    711     bool ready() { return fPixels != NULL; }
    712 private:
    713     void* fPixels;
    714     size_t fSize;
    715 };
    716 }  // namespace
    717 
    718 /*  This tests for a bug in libjpeg where INT32 is typedefed to long
    719     and memory can be written to outside of the array. */
    720 DEF_TEST(ImageDecoding_JpegOverwrite, r) {
    721     SkString resourceDir = GetResourcePath();
    722     SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.jpg");
    723     SkAutoTDelete<SkStreamAsset> stream(
    724             SkStream::NewFromFile(path.c_str()));
    725     if (!stream.get()) {
    726         SkDebugf("\nPath '%s' missing.\n", path.c_str());
    727         return;
    728     }
    729     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
    730     if (NULL == decoder.get()) {
    731         ERRORF(r, "\nSkImageDecoder::Factory failed.\n");
    732         return;
    733     }
    734     SkAssertResult(stream->rewind());
    735 
    736     static const uint16_t sentinal = 0xBEEF;
    737     static const int pixelCount = 16;
    738     SkAutoTMalloc<uint16_t> pixels(pixelCount + 1);
    739     // pixels.get() should be 4-byte aligned.
    740     // This is necessary to reproduce the bug.
    741 
    742     pixels[pixelCount] = sentinal;  // This value should not be changed.
    743 
    744     SkAutoTUnref<SingleAllocator> allocator(
    745             SkNEW_ARGS(SingleAllocator,
    746                        ((void*)pixels.get(), sizeof(uint16_t) * pixelCount)));
    747     decoder->setAllocator(allocator);
    748     decoder->setSampleSize(2);
    749     SkBitmap bitmap;
    750     bool success = decoder->decode(stream, &bitmap, kRGB_565_SkColorType,
    751                                    SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure;
    752     REPORTER_ASSERT(r, success);
    753     REPORTER_ASSERT(r, !allocator->ready());  // Decoder used correct memory
    754     REPORTER_ASSERT(r, sentinal == pixels[pixelCount]);
    755 }
    756