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