Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2015 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 "FakeStreams.h"
      9 #include "Resources.h"
     10 #include "SkAndroidCodec.h"
     11 #include "SkAutoMalloc.h"
     12 #include "SkBitmap.h"
     13 #include "SkCodec.h"
     14 #include "SkCodecImageGenerator.h"
     15 #include "SkColorSpace_XYZ.h"
     16 #include "SkColorSpacePriv.h"
     17 #include "SkData.h"
     18 #include "SkFrontBufferedStream.h"
     19 #include "SkImageEncoder.h"
     20 #include "SkImageEncoderPriv.h"
     21 #include "SkMakeUnique.h"
     22 #include "SkMD5.h"
     23 #include "SkOSPath.h"
     24 #include "SkJpegEncoder.h"
     25 #include "SkPngChunkReader.h"
     26 #include "SkPngEncoder.h"
     27 #include "SkRandom.h"
     28 #include "SkStream.h"
     29 #include "SkStreamPriv.h"
     30 #include "SkWebpEncoder.h"
     31 #include "Test.h"
     32 
     33 #include "png.h"
     34 
     35 #include "sk_tool_utils.h"
     36 
     37 #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 5
     38     // FIXME (scroggo): Google3 needs to be updated to use a newer version of libpng. In
     39     // the meantime, we had to break some pieces of SkPngCodec in order to support Google3.
     40     // The parts that are broken are likely not used by Google3.
     41     #define SK_PNG_DISABLE_TESTS
     42 #endif
     43 
     44 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) {
     45     SkASSERT(bm.getPixels());
     46     SkMD5 md5;
     47     size_t rowLen = bm.info().bytesPerPixel() * bm.width();
     48     for (int y = 0; y < bm.height(); ++y) {
     49         md5.write(bm.getAddr(0, y), rowLen);
     50     }
     51     md5.finish(*digest);
     52 }
     53 
     54 /**
     55  *  Compute the digest for bm and compare it to a known good digest.
     56  *  @param r Reporter to assert that bm's digest matches goodDigest.
     57  *  @param goodDigest The known good digest to compare to.
     58  *  @param bm The bitmap to test.
     59  */
     60 static void compare_to_good_digest(skiatest::Reporter* r, const SkMD5::Digest& goodDigest,
     61                            const SkBitmap& bm) {
     62     SkMD5::Digest digest;
     63     md5(bm, &digest);
     64     REPORTER_ASSERT(r, digest == goodDigest);
     65 }
     66 
     67 /**
     68  *  Test decoding an SkCodec to a particular SkImageInfo.
     69  *
     70  *  Calling getPixels(info) should return expectedResult, and if goodDigest is non nullptr,
     71  *  the resulting decode should match.
     72  */
     73 template<typename Codec>
     74 static void test_info(skiatest::Reporter* r, Codec* codec, const SkImageInfo& info,
     75                       SkCodec::Result expectedResult, const SkMD5::Digest* goodDigest) {
     76     SkBitmap bm;
     77     bm.allocPixels(info);
     78 
     79     SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
     80     REPORTER_ASSERT(r, result == expectedResult);
     81 
     82     if (goodDigest) {
     83         compare_to_good_digest(r, *goodDigest, bm);
     84     }
     85 }
     86 
     87 SkIRect generate_random_subset(SkRandom* rand, int w, int h) {
     88     SkIRect rect;
     89     do {
     90         rect.fLeft = rand->nextRangeU(0, w);
     91         rect.fTop = rand->nextRangeU(0, h);
     92         rect.fRight = rand->nextRangeU(0, w);
     93         rect.fBottom = rand->nextRangeU(0, h);
     94         rect.sort();
     95     } while (rect.isEmpty());
     96     return rect;
     97 }
     98 
     99 static void test_incremental_decode(skiatest::Reporter* r, SkCodec* codec, const SkImageInfo& info,
    100         const SkMD5::Digest& goodDigest) {
    101     SkBitmap bm;
    102     bm.allocPixels(info);
    103 
    104     REPORTER_ASSERT(r, SkCodec::kSuccess == codec->startIncrementalDecode(info, bm.getPixels(),
    105                                                                           bm.rowBytes()));
    106 
    107     REPORTER_ASSERT(r, SkCodec::kSuccess == codec->incrementalDecode());
    108 
    109     compare_to_good_digest(r, goodDigest, bm);
    110 }
    111 
    112 // Test in stripes, similar to DM's kStripe_Mode
    113 static void test_in_stripes(skiatest::Reporter* r, SkCodec* codec, const SkImageInfo& info,
    114                             const SkMD5::Digest& goodDigest) {
    115     SkBitmap bm;
    116     bm.allocPixels(info);
    117     bm.eraseColor(SK_ColorYELLOW);
    118 
    119     const int height = info.height();
    120     // Note that if numStripes does not evenly divide height there will be an extra
    121     // stripe.
    122     const int numStripes = 4;
    123 
    124     if (numStripes > height) {
    125         // Image is too small.
    126         return;
    127     }
    128 
    129     const int stripeHeight = height / numStripes;
    130 
    131     // Iterate through the image twice. Once to decode odd stripes, and once for even.
    132     for (int oddEven = 1; oddEven >= 0; oddEven--) {
    133         for (int y = oddEven * stripeHeight; y < height; y += 2 * stripeHeight) {
    134             SkIRect subset = SkIRect::MakeLTRB(0, y, info.width(),
    135                                                SkTMin(y + stripeHeight, height));
    136             SkCodec::Options options;
    137             options.fSubset = &subset;
    138             if (SkCodec::kSuccess != codec->startIncrementalDecode(info, bm.getAddr(0, y),
    139                         bm.rowBytes(), &options)) {
    140                 ERRORF(r, "failed to start incremental decode!\ttop: %i\tbottom%i\n",
    141                        subset.top(), subset.bottom());
    142                 return;
    143             }
    144             if (SkCodec::kSuccess != codec->incrementalDecode()) {
    145                 ERRORF(r, "failed incremental decode starting from line %i\n", y);
    146                 return;
    147             }
    148         }
    149     }
    150 
    151     compare_to_good_digest(r, goodDigest, bm);
    152 }
    153 
    154 template<typename Codec>
    155 static void test_codec(skiatest::Reporter* r, Codec* codec, SkBitmap& bm, const SkImageInfo& info,
    156         const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* digest,
    157         const SkMD5::Digest* goodDigest) {
    158 
    159     REPORTER_ASSERT(r, info.dimensions() == size);
    160     bm.allocPixels(info);
    161 
    162     SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
    163     REPORTER_ASSERT(r, result == expectedResult);
    164 
    165     md5(bm, digest);
    166     if (goodDigest) {
    167         REPORTER_ASSERT(r, *digest == *goodDigest);
    168     }
    169 
    170     {
    171         // Test decoding to 565
    172         SkImageInfo info565 = info.makeColorType(kRGB_565_SkColorType);
    173         if (info.alphaType() == kOpaque_SkAlphaType) {
    174             // Decoding to 565 should succeed.
    175             SkBitmap bm565;
    176             bm565.allocPixels(info565);
    177 
    178             // This will allow comparison even if the image is incomplete.
    179             bm565.eraseColor(SK_ColorBLACK);
    180 
    181             REPORTER_ASSERT(r, expectedResult == codec->getPixels(info565,
    182                     bm565.getPixels(), bm565.rowBytes()));
    183 
    184             SkMD5::Digest digest565;
    185             md5(bm565, &digest565);
    186 
    187             // A dumb client's request for non-opaque should also succeed.
    188             for (auto alpha : { kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
    189                 info565 = info565.makeAlphaType(alpha);
    190                 test_info(r, codec, info565, expectedResult, &digest565);
    191             }
    192         } else {
    193             test_info(r, codec, info565, SkCodec::kInvalidConversion, nullptr);
    194         }
    195     }
    196 
    197     if (codec->getInfo().colorType() == kGray_8_SkColorType) {
    198         SkImageInfo grayInfo = codec->getInfo();
    199         SkBitmap grayBm;
    200         grayBm.allocPixels(grayInfo);
    201 
    202         grayBm.eraseColor(SK_ColorBLACK);
    203 
    204         REPORTER_ASSERT(r, expectedResult == codec->getPixels(grayInfo,
    205                 grayBm.getPixels(), grayBm.rowBytes()));
    206 
    207         SkMD5::Digest grayDigest;
    208         md5(grayBm, &grayDigest);
    209 
    210         for (auto alpha : { kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
    211             grayInfo = grayInfo.makeAlphaType(alpha);
    212             test_info(r, codec, grayInfo, expectedResult, &grayDigest);
    213         }
    214     }
    215 
    216     // Verify that re-decoding gives the same result.  It is interesting to check this after
    217     // a decode to 565, since choosing to decode to 565 may result in some of the decode
    218     // options being modified.  These options should return to their defaults on another
    219     // decode to kN32, so the new digest should match the old digest.
    220     test_info(r, codec, info, expectedResult, digest);
    221 
    222     {
    223         // Check alpha type conversions
    224         if (info.alphaType() == kOpaque_SkAlphaType) {
    225             test_info(r, codec, info.makeAlphaType(kUnpremul_SkAlphaType),
    226                       expectedResult, digest);
    227             test_info(r, codec, info.makeAlphaType(kPremul_SkAlphaType),
    228                       expectedResult, digest);
    229         } else {
    230             // Decoding to opaque should fail
    231             test_info(r, codec, info.makeAlphaType(kOpaque_SkAlphaType),
    232                       SkCodec::kInvalidConversion, nullptr);
    233             SkAlphaType otherAt = info.alphaType();
    234             if (kPremul_SkAlphaType == otherAt) {
    235                 otherAt = kUnpremul_SkAlphaType;
    236             } else {
    237                 otherAt = kPremul_SkAlphaType;
    238             }
    239             // The other non-opaque alpha type should always succeed, but not match.
    240             test_info(r, codec, info.makeAlphaType(otherAt), expectedResult, nullptr);
    241         }
    242     }
    243 }
    244 
    245 static bool supports_partial_scanlines(const char path[]) {
    246     static const char* const exts[] = {
    247         "jpg", "jpeg", "png", "webp"
    248         "JPG", "JPEG", "PNG", "WEBP"
    249     };
    250 
    251     for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) {
    252         if (SkStrEndsWith(path, exts[i])) {
    253             return true;
    254         }
    255     }
    256     return false;
    257 }
    258 
    259 // FIXME: Break up this giant function
    260 static void check(skiatest::Reporter* r,
    261                   const char path[],
    262                   SkISize size,
    263                   bool supportsScanlineDecoding,
    264                   bool supportsSubsetDecoding,
    265                   bool supportsIncomplete,
    266                   bool supportsNewScanlineDecoding = false) {
    267 
    268     std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    269     if (!stream) {
    270         return;
    271     }
    272 
    273     std::unique_ptr<SkCodec> codec(nullptr);
    274     bool isIncomplete = supportsIncomplete;
    275     if (isIncomplete) {
    276         size_t size = stream->getLength();
    277         codec = SkCodec::MakeFromData(SkData::MakeFromStream(stream.get(), 2 * size / 3));
    278     } else {
    279         codec = SkCodec::MakeFromStream(std::move(stream));
    280     }
    281     if (!codec) {
    282         ERRORF(r, "Unable to decode '%s'", path);
    283         return;
    284     }
    285 
    286     // Test full image decodes with SkCodec
    287     SkMD5::Digest codecDigest;
    288     const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
    289     SkBitmap bm;
    290     SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput : SkCodec::kSuccess;
    291     test_codec(r, codec.get(), bm, info, size, expectedResult, &codecDigest, nullptr);
    292 
    293     // Scanline decoding follows.
    294 
    295     if (supportsNewScanlineDecoding && !isIncomplete) {
    296         test_incremental_decode(r, codec.get(), info, codecDigest);
    297         // This is only supported by codecs that use incremental decoding to
    298         // support subset decodes - png and jpeg (once SkJpegCodec is
    299         // converted).
    300         if (SkStrEndsWith(path, "png") || SkStrEndsWith(path, "PNG")) {
    301             test_in_stripes(r, codec.get(), info, codecDigest);
    302         }
    303     }
    304 
    305     // Need to call startScanlineDecode() first.
    306     REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) == 0);
    307     REPORTER_ASSERT(r, !codec->skipScanlines(1));
    308     const SkCodec::Result startResult = codec->startScanlineDecode(info);
    309     if (supportsScanlineDecoding) {
    310         bm.eraseColor(SK_ColorYELLOW);
    311 
    312         REPORTER_ASSERT(r, startResult == SkCodec::kSuccess);
    313 
    314         for (int y = 0; y < info.height(); y++) {
    315             const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0);
    316             if (!isIncomplete) {
    317                 REPORTER_ASSERT(r, 1 == lines);
    318             }
    319         }
    320         // verify that scanline decoding gives the same result.
    321         if (SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()) {
    322             compare_to_good_digest(r, codecDigest, bm);
    323         }
    324 
    325         // Cannot continue to decode scanlines beyond the end
    326         REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0)
    327                 == 0);
    328 
    329         // Interrupting a scanline decode with a full decode starts from
    330         // scratch
    331         REPORTER_ASSERT(r, codec->startScanlineDecode(info) == SkCodec::kSuccess);
    332         const int lines = codec->getScanlines(bm.getAddr(0, 0), 1, 0);
    333         if (!isIncomplete) {
    334             REPORTER_ASSERT(r, lines == 1);
    335         }
    336         REPORTER_ASSERT(r, codec->getPixels(bm.info(), bm.getPixels(), bm.rowBytes())
    337                 == expectedResult);
    338         REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0)
    339                 == 0);
    340         REPORTER_ASSERT(r, codec->skipScanlines(1)
    341                 == 0);
    342 
    343         // Test partial scanline decodes
    344         if (supports_partial_scanlines(path) && info.width() >= 3) {
    345             SkCodec::Options options;
    346             int width = info.width();
    347             int height = info.height();
    348             SkIRect subset = SkIRect::MakeXYWH(2 * (width / 3), 0, width / 3, height);
    349             options.fSubset = &subset;
    350 
    351             const auto partialStartResult = codec->startScanlineDecode(info, &options);
    352             REPORTER_ASSERT(r, partialStartResult == SkCodec::kSuccess);
    353 
    354             for (int y = 0; y < height; y++) {
    355                 const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0);
    356                 if (!isIncomplete) {
    357                     REPORTER_ASSERT(r, 1 == lines);
    358                 }
    359             }
    360         }
    361     } else {
    362         REPORTER_ASSERT(r, startResult == SkCodec::kUnimplemented);
    363     }
    364 
    365     // The rest of this function tests decoding subsets, and will decode an arbitrary number of
    366     // random subsets.
    367     // Do not attempt to decode subsets of an image of only once pixel, since there is no
    368     // meaningful subset.
    369     if (size.width() * size.height() == 1) {
    370         return;
    371     }
    372 
    373     SkRandom rand;
    374     SkIRect subset;
    375     SkCodec::Options opts;
    376     opts.fSubset = &subset;
    377     for (int i = 0; i < 5; i++) {
    378         subset = generate_random_subset(&rand, size.width(), size.height());
    379         SkASSERT(!subset.isEmpty());
    380         const bool supported = codec->getValidSubset(&subset);
    381         REPORTER_ASSERT(r, supported == supportsSubsetDecoding);
    382 
    383         SkImageInfo subsetInfo = info.makeWH(subset.width(), subset.height());
    384         SkBitmap bm;
    385         bm.allocPixels(subsetInfo);
    386         const auto result = codec->getPixels(bm.info(), bm.getPixels(), bm.rowBytes(), &opts);
    387 
    388         if (supportsSubsetDecoding) {
    389             if (expectedResult == SkCodec::kSuccess) {
    390                 REPORTER_ASSERT(r, result == expectedResult);
    391             }
    392             // Webp is the only codec that supports subsets, and it will have modified the subset
    393             // to have even left/top.
    394             REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTop));
    395         } else {
    396             // No subsets will work.
    397             REPORTER_ASSERT(r, result == SkCodec::kUnimplemented);
    398         }
    399     }
    400 
    401     // SkAndroidCodec tests
    402     if (supportsScanlineDecoding || supportsSubsetDecoding || supportsNewScanlineDecoding) {
    403 
    404         std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    405         if (!stream) {
    406             return;
    407         }
    408 
    409         auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
    410         if (!androidCodec) {
    411             ERRORF(r, "Unable to decode '%s'", path);
    412             return;
    413         }
    414 
    415         SkBitmap bm;
    416         SkMD5::Digest androidCodecDigest;
    417         test_codec(r, androidCodec.get(), bm, info, size, expectedResult, &androidCodecDigest,
    418                    &codecDigest);
    419     }
    420 
    421     if (!isIncomplete) {
    422         // Test SkCodecImageGenerator
    423         std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    424         sk_sp<SkData> fullData(SkData::MakeFromStream(stream.get(), stream->getLength()));
    425         std::unique_ptr<SkImageGenerator> gen(
    426                 SkCodecImageGenerator::MakeFromEncodedCodec(fullData));
    427         SkBitmap bm;
    428         bm.allocPixels(info);
    429         REPORTER_ASSERT(r, gen->getPixels(info, bm.getPixels(), bm.rowBytes()));
    430         compare_to_good_digest(r, codecDigest, bm);
    431 
    432 #ifndef SK_PNG_DISABLE_TESTS
    433         // Test using SkFrontBufferedStream, as Android does
    434         auto bufferedStream = SkFrontBufferedStream::Make(
    435                       SkMemoryStream::Make(std::move(fullData)), SkCodec::MinBufferedBytesNeeded());
    436         REPORTER_ASSERT(r, bufferedStream);
    437         codec = SkCodec::MakeFromStream(std::move(bufferedStream));
    438         REPORTER_ASSERT(r, codec);
    439         if (codec) {
    440             test_info(r, codec.get(), info, SkCodec::kSuccess, &codecDigest);
    441         }
    442 #endif
    443     }
    444 
    445     // If we've just tested incomplete decodes, let's run the same test again on full decodes.
    446     if (isIncomplete) {
    447         check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding, false,
    448               supportsNewScanlineDecoding);
    449     }
    450 }
    451 
    452 DEF_TEST(Codec_wbmp, r) {
    453     check(r, "images/mandrill.wbmp", SkISize::Make(512, 512), true, false, true);
    454 }
    455 
    456 DEF_TEST(Codec_webp, r) {
    457     check(r, "images/baby_tux.webp", SkISize::Make(386, 395), false, true, true);
    458     check(r, "images/color_wheel.webp", SkISize::Make(128, 128), false, true, true);
    459     check(r, "images/yellow_rose.webp", SkISize::Make(400, 301), false, true, true);
    460 }
    461 
    462 DEF_TEST(Codec_bmp, r) {
    463     check(r, "images/randPixels.bmp", SkISize::Make(8, 8), true, false, true);
    464     check(r, "images/rle.bmp", SkISize::Make(320, 240), true, false, true);
    465 }
    466 
    467 DEF_TEST(Codec_ico, r) {
    468     // FIXME: We are not ready to test incomplete ICOs
    469     // These two tests examine interestingly different behavior:
    470     // Decodes an embedded BMP image
    471     check(r, "images/color_wheel.ico", SkISize::Make(128, 128), true, false, false);
    472     // Decodes an embedded PNG image
    473     check(r, "images/google_chrome.ico", SkISize::Make(256, 256), false, false, false, true);
    474 }
    475 
    476 DEF_TEST(Codec_gif, r) {
    477     check(r, "images/box.gif", SkISize::Make(200, 55), false, false, true, true);
    478     check(r, "images/color_wheel.gif", SkISize::Make(128, 128), false, false, true, true);
    479     // randPixels.gif is too small to test incomplete
    480     check(r, "images/randPixels.gif", SkISize::Make(8, 8), false, false, false, true);
    481 }
    482 
    483 DEF_TEST(Codec_jpg, r) {
    484     check(r, "images/CMYK.jpg", SkISize::Make(642, 516), true, false, true);
    485     check(r, "images/color_wheel.jpg", SkISize::Make(128, 128), true, false, true);
    486     // grayscale.jpg is too small to test incomplete
    487     check(r, "images/grayscale.jpg", SkISize::Make(128, 128), true, false, false);
    488     check(r, "images/mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false, true);
    489     // randPixels.jpg is too small to test incomplete
    490     check(r, "images/randPixels.jpg", SkISize::Make(8, 8), true, false, false);
    491 }
    492 
    493 DEF_TEST(Codec_png, r) {
    494     check(r, "images/arrow.png", SkISize::Make(187, 312), false, false, true, true);
    495     check(r, "images/baby_tux.png", SkISize::Make(240, 246), false, false, true, true);
    496     check(r, "images/color_wheel.png", SkISize::Make(128, 128), false, false, true, true);
    497     // half-transparent-white-pixel.png is too small to test incomplete
    498     check(r, "images/half-transparent-white-pixel.png", SkISize::Make(1, 1), false, false, false, true);
    499     check(r, "images/mandrill_128.png", SkISize::Make(128, 128), false, false, true, true);
    500     check(r, "images/mandrill_16.png", SkISize::Make(16, 16), false, false, true, true);
    501     check(r, "images/mandrill_256.png", SkISize::Make(256, 256), false, false, true, true);
    502     check(r, "images/mandrill_32.png", SkISize::Make(32, 32), false, false, true, true);
    503     check(r, "images/mandrill_512.png", SkISize::Make(512, 512), false, false, true, true);
    504     check(r, "images/mandrill_64.png", SkISize::Make(64, 64), false, false, true, true);
    505     check(r, "images/plane.png", SkISize::Make(250, 126), false, false, true, true);
    506     check(r, "images/plane_interlaced.png", SkISize::Make(250, 126), false, false, true, true);
    507     check(r, "images/randPixels.png", SkISize::Make(8, 8), false, false, true, true);
    508     check(r, "images/yellow_rose.png", SkISize::Make(400, 301), false, false, true, true);
    509 }
    510 
    511 // Disable RAW tests for Win32.
    512 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
    513 DEF_TEST(Codec_raw, r) {
    514     check(r, "images/sample_1mp.dng", SkISize::Make(600, 338), false, false, false);
    515     check(r, "images/sample_1mp_rotated.dng", SkISize::Make(600, 338), false, false, false);
    516     check(r, "images/dng_with_preview.dng", SkISize::Make(600, 338), true, false, false);
    517 }
    518 #endif
    519 
    520 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_t len) {
    521     // Neither of these calls should return a codec. Bots should catch us if we leaked anything.
    522     REPORTER_ASSERT(r, !SkCodec::MakeFromStream(
    523                                         skstd::make_unique<SkMemoryStream>(stream, len, false)));
    524     REPORTER_ASSERT(r, !SkAndroidCodec::MakeFromStream(
    525                                         skstd::make_unique<SkMemoryStream>(stream, len, false)));
    526 }
    527 
    528 // Ensure that SkCodec::NewFromStream handles freeing the passed in SkStream,
    529 // even on failure. Test some bad streams.
    530 DEF_TEST(Codec_leaks, r) {
    531     // No codec should claim this as their format, so this tests SkCodec::NewFromStream.
    532     const char nonSupportedStream[] = "hello world";
    533     // The other strings should look like the beginning of a file type, so we'll call some
    534     // internal version of NewFromStream, which must also delete the stream on failure.
    535     const unsigned char emptyPng[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
    536     const unsigned char emptyJpeg[] = { 0xFF, 0xD8, 0xFF };
    537     const char emptyWebp[] = "RIFF1234WEBPVP";
    538     const char emptyBmp[] = { 'B', 'M' };
    539     const char emptyIco[] = { '\x00', '\x00', '\x01', '\x00' };
    540     const char emptyGif[] = "GIFVER";
    541 
    542     test_invalid_stream(r, nonSupportedStream, sizeof(nonSupportedStream));
    543     test_invalid_stream(r, emptyPng, sizeof(emptyPng));
    544     test_invalid_stream(r, emptyJpeg, sizeof(emptyJpeg));
    545     test_invalid_stream(r, emptyWebp, sizeof(emptyWebp));
    546     test_invalid_stream(r, emptyBmp, sizeof(emptyBmp));
    547     test_invalid_stream(r, emptyIco, sizeof(emptyIco));
    548     test_invalid_stream(r, emptyGif, sizeof(emptyGif));
    549 }
    550 
    551 DEF_TEST(Codec_null, r) {
    552     // Attempting to create an SkCodec or an SkAndroidCodec with null should not
    553     // crash.
    554     REPORTER_ASSERT(r, !SkCodec::MakeFromStream(nullptr));
    555     REPORTER_ASSERT(r, !SkAndroidCodec::MakeFromStream(nullptr));
    556 }
    557 
    558 static void test_dimensions(skiatest::Reporter* r, const char path[]) {
    559     // Create the codec from the resource file
    560     std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    561     if (!stream) {
    562         return;
    563     }
    564     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(std::move(stream)));
    565     if (!codec) {
    566         ERRORF(r, "Unable to create codec '%s'", path);
    567         return;
    568     }
    569 
    570     // Check that the decode is successful for a variety of scales
    571     for (int sampleSize = 1; sampleSize < 32; sampleSize++) {
    572         // Scale the output dimensions
    573         SkISize scaledDims = codec->getSampledDimensions(sampleSize);
    574         SkImageInfo scaledInfo = codec->getInfo()
    575                 .makeWH(scaledDims.width(), scaledDims.height())
    576                 .makeColorType(kN32_SkColorType);
    577 
    578         // Set up for the decode
    579         size_t rowBytes = scaledDims.width() * sizeof(SkPMColor);
    580         size_t totalBytes = scaledInfo.computeByteSize(rowBytes);
    581         SkAutoTMalloc<SkPMColor> pixels(totalBytes);
    582 
    583         SkAndroidCodec::AndroidOptions options;
    584         options.fSampleSize = sampleSize;
    585         SkCodec::Result result =
    586                 codec->getAndroidPixels(scaledInfo, pixels.get(), rowBytes, &options);
    587         REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    588     }
    589 }
    590 
    591 // Ensure that onGetScaledDimensions returns valid image dimensions to use for decodes
    592 DEF_TEST(Codec_Dimensions, r) {
    593     // JPG
    594     test_dimensions(r, "images/CMYK.jpg");
    595     test_dimensions(r, "images/color_wheel.jpg");
    596     test_dimensions(r, "images/grayscale.jpg");
    597     test_dimensions(r, "images/mandrill_512_q075.jpg");
    598     test_dimensions(r, "images/randPixels.jpg");
    599 
    600     // Decoding small images with very large scaling factors is a potential
    601     // source of bugs and crashes.  We disable these tests in Gold because
    602     // tiny images are not very useful to look at.
    603     // Here we make sure that we do not crash or access illegal memory when
    604     // performing scaled decodes on small images.
    605     test_dimensions(r, "images/1x1.png");
    606     test_dimensions(r, "images/2x2.png");
    607     test_dimensions(r, "images/3x3.png");
    608     test_dimensions(r, "images/3x1.png");
    609     test_dimensions(r, "images/1x1.png");
    610     test_dimensions(r, "images/16x1.png");
    611     test_dimensions(r, "images/1x16.png");
    612     test_dimensions(r, "images/mandrill_16.png");
    613 
    614     // RAW
    615 // Disable RAW tests for Win32.
    616 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
    617     test_dimensions(r, "images/sample_1mp.dng");
    618     test_dimensions(r, "images/sample_1mp_rotated.dng");
    619     test_dimensions(r, "images/dng_with_preview.dng");
    620 #endif
    621 }
    622 
    623 static void test_invalid(skiatest::Reporter* r, const char path[]) {
    624     std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    625     if (!stream) {
    626         return;
    627     }
    628     REPORTER_ASSERT(r, !SkCodec::MakeFromStream(std::move(stream)));
    629 }
    630 
    631 DEF_TEST(Codec_Empty, r) {
    632     // Test images that should not be able to create a codec
    633     test_invalid(r, "empty_images/zero-dims.gif");
    634     test_invalid(r, "empty_images/zero-embedded.ico");
    635     test_invalid(r, "empty_images/zero-width.bmp");
    636     test_invalid(r, "empty_images/zero-height.bmp");
    637     test_invalid(r, "empty_images/zero-width.jpg");
    638     test_invalid(r, "empty_images/zero-height.jpg");
    639     test_invalid(r, "empty_images/zero-width.png");
    640     test_invalid(r, "empty_images/zero-height.png");
    641     test_invalid(r, "empty_images/zero-width.wbmp");
    642     test_invalid(r, "empty_images/zero-height.wbmp");
    643     // This image is an ico with an embedded mask-bmp.  This is illegal.
    644     test_invalid(r, "invalid_images/mask-bmp-ico.ico");
    645     // It is illegal for a webp frame to not be fully contained by the canvas.
    646     test_invalid(r, "invalid_images/invalid-offset.webp");
    647 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
    648     test_invalid(r, "empty_images/zero_height.tiff");
    649 #endif
    650     test_invalid(r, "invalid_images/b37623797.ico");
    651 }
    652 
    653 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
    654 
    655 #ifndef SK_PNG_DISABLE_TESTS   // reading chunks does not work properly with older versions.
    656                                // It does not appear that anyone in Google3 is reading chunks.
    657 
    658 static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
    659     SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr);
    660     if (!sk_stream->write(data, len)) {
    661         png_error(png_ptr, "sk_write_fn Error!");
    662     }
    663 }
    664 
    665 DEF_TEST(Codec_pngChunkReader, r) {
    666     // Create a dummy bitmap. Use unpremul RGBA for libpng.
    667     SkBitmap bm;
    668     const int w = 1;
    669     const int h = 1;
    670     const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
    671                                                  kUnpremul_SkAlphaType);
    672     bm.setInfo(bmInfo);
    673     bm.allocPixels();
    674     bm.eraseColor(SK_ColorBLUE);
    675     SkMD5::Digest goodDigest;
    676     md5(bm, &goodDigest);
    677 
    678     // Write to a png file.
    679     png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    680     REPORTER_ASSERT(r, png);
    681     if (!png) {
    682         return;
    683     }
    684 
    685     png_infop info = png_create_info_struct(png);
    686     REPORTER_ASSERT(r, info);
    687     if (!info) {
    688         png_destroy_write_struct(&png, nullptr);
    689         return;
    690     }
    691 
    692     if (setjmp(png_jmpbuf(png))) {
    693         ERRORF(r, "failed writing png");
    694         png_destroy_write_struct(&png, &info);
    695         return;
    696     }
    697 
    698     SkDynamicMemoryWStream wStream;
    699     png_set_write_fn(png, (void*) (&wStream), codex_test_write_fn, nullptr);
    700 
    701     png_set_IHDR(png, info, (png_uint_32)w, (png_uint_32)h, 8,
    702                  PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
    703                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
    704 
    705     // Create some chunks that match the Android framework's use.
    706     static png_unknown_chunk gUnknowns[] = {
    707         { "npOl", (png_byte*)"outline", sizeof("outline"), PNG_HAVE_IHDR },
    708         { "npLb", (png_byte*)"layoutBounds", sizeof("layoutBounds"), PNG_HAVE_IHDR },
    709         { "npTc", (png_byte*)"ninePatchData", sizeof("ninePatchData"), PNG_HAVE_IHDR },
    710     };
    711 
    712     png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"npOl\0npLb\0npTc\0", 3);
    713     png_set_unknown_chunks(png, info, gUnknowns, SK_ARRAY_COUNT(gUnknowns));
    714 #if PNG_LIBPNG_VER < 10600
    715     /* Deal with unknown chunk location bug in 1.5.x and earlier */
    716     png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_IHDR);
    717     png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_IHDR);
    718 #endif
    719 
    720     png_write_info(png, info);
    721 
    722     for (int j = 0; j < h; j++) {
    723         png_bytep row = (png_bytep)(bm.getAddr(0, j));
    724         png_write_rows(png, &row, 1);
    725     }
    726     png_write_end(png, info);
    727     png_destroy_write_struct(&png, &info);
    728 
    729     class ChunkReader : public SkPngChunkReader {
    730     public:
    731         ChunkReader(skiatest::Reporter* r)
    732             : fReporter(r)
    733         {
    734             this->reset();
    735         }
    736 
    737         bool readChunk(const char tag[], const void* data, size_t length) override {
    738             for (size_t i = 0; i < SK_ARRAY_COUNT(gUnknowns); ++i) {
    739                 if (!strcmp(tag, (const char*) gUnknowns[i].name)) {
    740                     // Tag matches. This should have been the first time we see it.
    741                     REPORTER_ASSERT(fReporter, !fSeen[i]);
    742                     fSeen[i] = true;
    743 
    744                     // Data and length should match
    745                     REPORTER_ASSERT(fReporter, length == gUnknowns[i].size);
    746                     REPORTER_ASSERT(fReporter, !strcmp((const char*) data,
    747                                                        (const char*) gUnknowns[i].data));
    748                     return true;
    749                 }
    750             }
    751             ERRORF(fReporter, "Saw an unexpected unknown chunk.");
    752             return true;
    753         }
    754 
    755         bool allHaveBeenSeen() {
    756             bool ret = true;
    757             for (auto seen : fSeen) {
    758                 ret &= seen;
    759             }
    760             return ret;
    761         }
    762 
    763         void reset() {
    764             sk_bzero(fSeen, sizeof(fSeen));
    765         }
    766 
    767     private:
    768         skiatest::Reporter* fReporter;  // Unowned
    769         bool fSeen[3];
    770     };
    771 
    772     ChunkReader chunkReader(r);
    773 
    774     // Now read the file with SkCodec.
    775     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(wStream.detachAsData(), &chunkReader));
    776     REPORTER_ASSERT(r, codec);
    777     if (!codec) {
    778         return;
    779     }
    780 
    781     // Now compare to the original.
    782     SkBitmap decodedBm;
    783     decodedBm.setInfo(codec->getInfo());
    784     decodedBm.allocPixels();
    785     SkCodec::Result result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(),
    786                                               decodedBm.rowBytes());
    787     REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    788 
    789     if (decodedBm.colorType() != bm.colorType()) {
    790         SkBitmap tmp;
    791         bool success = sk_tool_utils::copy_to(&tmp, bm.colorType(), decodedBm);
    792         REPORTER_ASSERT(r, success);
    793         if (!success) {
    794             return;
    795         }
    796 
    797         tmp.swap(decodedBm);
    798     }
    799 
    800     compare_to_good_digest(r, goodDigest, decodedBm);
    801     REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
    802 
    803     // Decoding again will read the chunks again.
    804     chunkReader.reset();
    805     REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen());
    806     result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm.rowBytes());
    807     REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    808     REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
    809 }
    810 #endif // SK_PNG_DISABLE_TESTS
    811 #endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
    812 
    813 // Stream that can only peek up to a limit
    814 class LimitedPeekingMemStream : public SkStream {
    815 public:
    816     LimitedPeekingMemStream(sk_sp<SkData> data, size_t limit)
    817         : fStream(std::move(data))
    818         , fLimit(limit) {}
    819 
    820     size_t peek(void* buf, size_t bytes) const override {
    821         return fStream.peek(buf, SkTMin(bytes, fLimit));
    822     }
    823     size_t read(void* buf, size_t bytes) override {
    824         return fStream.read(buf, bytes);
    825     }
    826     bool rewind() override {
    827         return fStream.rewind();
    828     }
    829     bool isAtEnd() const override {
    830         return fStream.isAtEnd();
    831     }
    832 private:
    833     SkMemoryStream fStream;
    834     const size_t   fLimit;
    835 };
    836 
    837 // Disable RAW tests for Win32.
    838 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
    839 // Test that the RawCodec works also for not asset stream. This will test the code path using
    840 // SkRawBufferedStream instead of SkRawAssetStream.
    841 DEF_TEST(Codec_raw_notseekable, r) {
    842     constexpr char path[] = "images/dng_with_preview.dng";
    843     sk_sp<SkData> data(GetResourceAsData(path));
    844     if (!data) {
    845         SkDebugf("Missing resource '%s'\n", path);
    846         return;
    847     }
    848 
    849     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(
    850                                            skstd::make_unique<NotAssetMemStream>(std::move(data))));
    851     REPORTER_ASSERT(r, codec);
    852 
    853     test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
    854 }
    855 #endif
    856 
    857 // Test that even if webp_parse_header fails to peek enough, it will fall back to read()
    858 // + rewind() and succeed.
    859 DEF_TEST(Codec_webp_peek, r) {
    860     constexpr char path[] = "images/baby_tux.webp";
    861     auto data = GetResourceAsData(path);
    862     if (!data) {
    863         SkDebugf("Missing resource '%s'\n", path);
    864         return;
    865     }
    866 
    867     // The limit is less than webp needs to peek or read.
    868     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(
    869                                            skstd::make_unique<LimitedPeekingMemStream>(data, 25)));
    870     REPORTER_ASSERT(r, codec);
    871 
    872     test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
    873 
    874     // Similarly, a stream which does not peek should still succeed.
    875     codec = SkCodec::MakeFromStream(skstd::make_unique<LimitedPeekingMemStream>(data, 0));
    876     REPORTER_ASSERT(r, codec);
    877 
    878     test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
    879 }
    880 
    881 // SkCodec's wbmp decoder was initially unnecessarily restrictive.
    882 // It required the second byte to be zero. The wbmp specification allows
    883 // a couple of bits to be 1 (so long as they do not overlap with 0x9F).
    884 // Test that SkCodec now supports an image with these bits set.
    885 DEF_TEST(Codec_wbmp_restrictive, r) {
    886     const char* path = "images/mandrill.wbmp";
    887     std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
    888     if (!stream) {
    889         return;
    890     }
    891 
    892     // Modify the stream to contain a second byte with some bits set.
    893     auto data = SkCopyStreamToData(stream.get());
    894     uint8_t* writeableData = static_cast<uint8_t*>(data->writable_data());
    895     writeableData[1] = static_cast<uint8_t>(~0x9F);
    896 
    897     // SkCodec should support this.
    898     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
    899     REPORTER_ASSERT(r, codec);
    900     if (!codec) {
    901         return;
    902     }
    903     test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
    904 }
    905 
    906 // wbmp images have a header that can be arbitrarily large, depending on the
    907 // size of the image. We cap the size at 65535, meaning we only need to look at
    908 // 8 bytes to determine whether we can read the image. This is important
    909 // because SkCodec only passes a limited number of bytes to SkWbmpCodec to
    910 // determine whether the image is a wbmp.
    911 DEF_TEST(Codec_wbmp_max_size, r) {
    912     const unsigned char maxSizeWbmp[] = { 0x00, 0x00,           // Header
    913                                           0x83, 0xFF, 0x7F,     // W: 65535
    914                                           0x83, 0xFF, 0x7F };   // H: 65535
    915     std::unique_ptr<SkStream> stream(new SkMemoryStream(maxSizeWbmp, sizeof(maxSizeWbmp), false));
    916     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
    917 
    918     REPORTER_ASSERT(r, codec);
    919     if (!codec) return;
    920 
    921     REPORTER_ASSERT(r, codec->getInfo().width() == 65535);
    922     REPORTER_ASSERT(r, codec->getInfo().height() == 65535);
    923 
    924     // Now test an image which is too big. Any image with a larger header (i.e.
    925     // has bigger width/height) is also too big.
    926     const unsigned char tooBigWbmp[] = { 0x00, 0x00,           // Header
    927                                          0x84, 0x80, 0x00,     // W: 65536
    928                                          0x84, 0x80, 0x00 };   // H: 65536
    929     stream.reset(new SkMemoryStream(tooBigWbmp, sizeof(tooBigWbmp), false));
    930     codec = SkCodec::MakeFromStream(std::move(stream));
    931 
    932     REPORTER_ASSERT(r, !codec);
    933 }
    934 
    935 DEF_TEST(Codec_jpeg_rewind, r) {
    936     const char* path = "images/mandrill_512_q075.jpg";
    937     sk_sp<SkData> data(GetResourceAsData(path));
    938     if (!data) {
    939         return;
    940     }
    941 
    942     data = SkData::MakeSubset(data.get(), 0, data->size() / 2);
    943     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(data));
    944     if (!codec) {
    945         ERRORF(r, "Unable to create codec '%s'.", path);
    946         return;
    947     }
    948 
    949     const int width = codec->getInfo().width();
    950     const int height = codec->getInfo().height();
    951     size_t rowBytes = sizeof(SkPMColor) * width;
    952     SkAutoMalloc pixelStorage(height * rowBytes);
    953 
    954     // Perform a sampled decode.
    955     SkAndroidCodec::AndroidOptions opts;
    956     opts.fSampleSize = 12;
    957     auto sampledInfo = codec->getInfo().makeWH(width / 12, height / 12);
    958     auto result = codec->getAndroidPixels(sampledInfo, pixelStorage.get(), rowBytes, &opts);
    959     REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
    960 
    961     // Rewind the codec and perform a full image decode.
    962     result = codec->getPixels(codec->getInfo(), pixelStorage.get(), rowBytes);
    963     REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
    964 
    965     // Now perform a subset decode.
    966     {
    967         opts.fSampleSize = 1;
    968         SkIRect subset = SkIRect::MakeWH(100, 100);
    969         opts.fSubset = &subset;
    970         result = codec->getAndroidPixels(codec->getInfo().makeWH(100, 100), pixelStorage.get(),
    971                                          rowBytes, &opts);
    972         // Though we only have half the data, it is enough to decode this subset.
    973         REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    974     }
    975 
    976     // Perform another full image decode.  ASAN will detect if we look at the subset when it is
    977     // out of scope.  This would happen if we depend on the old state in the codec.
    978     // This tests two layers of bugs: both SkJpegCodec::readRows and SkCodec::fillIncompleteImage
    979     // used to look at the old subset.
    980     opts.fSubset = nullptr;
    981     result = codec->getAndroidPixels(codec->getInfo(), pixelStorage.get(), rowBytes, &opts);
    982     REPORTER_ASSERT(r, SkCodec::kIncompleteInput == result);
    983 }
    984 
    985 static void check_color_xform(skiatest::Reporter* r, const char* path) {
    986     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(GetResourceAsStream(path)));
    987 
    988     SkAndroidCodec::AndroidOptions opts;
    989     opts.fSampleSize = 3;
    990     const int subsetWidth = codec->getInfo().width() / 2;
    991     const int subsetHeight = codec->getInfo().height() / 2;
    992     SkIRect subset = SkIRect::MakeWH(subsetWidth, subsetHeight);
    993     opts.fSubset = &subset;
    994 
    995     const int dstWidth = subsetWidth / opts.fSampleSize;
    996     const int dstHeight = subsetHeight / opts.fSampleSize;
    997     sk_sp<SkData> data = GetResourceAsData("icc_profiles/HP_ZR30w.icc");
    998     sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeICC(data->data(), data->size());
    999     SkImageInfo dstInfo = codec->getInfo().makeWH(dstWidth, dstHeight)
   1000                                           .makeColorType(kN32_SkColorType)
   1001                                           .makeColorSpace(colorSpace);
   1002 
   1003     size_t rowBytes = dstInfo.minRowBytes();
   1004     SkAutoMalloc pixelStorage(dstInfo.computeByteSize(rowBytes));
   1005     SkCodec::Result result = codec->getAndroidPixels(dstInfo, pixelStorage.get(), rowBytes, &opts);
   1006     REPORTER_ASSERT(r, SkCodec::kSuccess == result);
   1007 }
   1008 
   1009 DEF_TEST(Codec_ColorXform, r) {
   1010     check_color_xform(r, "images/mandrill_512_q075.jpg");
   1011     check_color_xform(r, "images/mandrill_512.png");
   1012 }
   1013 
   1014 static bool color_type_match(SkColorType origColorType, SkColorType codecColorType) {
   1015     switch (origColorType) {
   1016         case kRGBA_8888_SkColorType:
   1017         case kBGRA_8888_SkColorType:
   1018             return kRGBA_8888_SkColorType == codecColorType ||
   1019                    kBGRA_8888_SkColorType == codecColorType;
   1020         default:
   1021             return origColorType == codecColorType;
   1022     }
   1023 }
   1024 
   1025 static bool alpha_type_match(SkAlphaType origAlphaType, SkAlphaType codecAlphaType) {
   1026     switch (origAlphaType) {
   1027         case kUnpremul_SkAlphaType:
   1028         case kPremul_SkAlphaType:
   1029             return kUnpremul_SkAlphaType == codecAlphaType ||
   1030                     kPremul_SkAlphaType == codecAlphaType;
   1031         default:
   1032             return origAlphaType == codecAlphaType;
   1033     }
   1034 }
   1035 
   1036 static void check_round_trip(skiatest::Reporter* r, SkCodec* origCodec, const SkImageInfo& info) {
   1037     SkBitmap bm1;
   1038     bm1.allocPixels(info);
   1039     SkCodec::Result result = origCodec->getPixels(info, bm1.getPixels(), bm1.rowBytes());
   1040     REPORTER_ASSERT(r, SkCodec::kSuccess == result);
   1041 
   1042     // Encode the image to png.
   1043     sk_sp<SkData> data =
   1044             sk_sp<SkData>(sk_tool_utils::EncodeImageToData(bm1, SkEncodedImageFormat::kPNG, 100));
   1045 
   1046     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
   1047     REPORTER_ASSERT(r, color_type_match(info.colorType(), codec->getInfo().colorType()));
   1048     REPORTER_ASSERT(r, alpha_type_match(info.alphaType(), codec->getInfo().alphaType()));
   1049 
   1050     SkBitmap bm2;
   1051     bm2.allocPixels(info);
   1052     result = codec->getPixels(info, bm2.getPixels(), bm2.rowBytes());
   1053     REPORTER_ASSERT(r, SkCodec::kSuccess == result);
   1054 
   1055     SkMD5::Digest d1, d2;
   1056     md5(bm1, &d1);
   1057     md5(bm2, &d2);
   1058     REPORTER_ASSERT(r, d1 == d2);
   1059 }
   1060 
   1061 DEF_TEST(Codec_PngRoundTrip, r) {
   1062     auto codec = SkCodec::MakeFromStream(GetResourceAsStream("images/mandrill_512_q075.jpg"));
   1063 
   1064     SkColorType colorTypesOpaque[] = {
   1065             kRGB_565_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType
   1066     };
   1067     for (SkColorType colorType : colorTypesOpaque) {
   1068         SkImageInfo newInfo = codec->getInfo().makeColorType(colorType);
   1069         check_round_trip(r, codec.get(), newInfo);
   1070     }
   1071 
   1072     codec = SkCodec::MakeFromStream(GetResourceAsStream("images/grayscale.jpg"));
   1073     check_round_trip(r, codec.get(), codec->getInfo());
   1074 
   1075     codec = SkCodec::MakeFromStream(GetResourceAsStream("images/yellow_rose.png"));
   1076 
   1077     SkColorType colorTypesWithAlpha[] = {
   1078             kRGBA_8888_SkColorType, kBGRA_8888_SkColorType
   1079     };
   1080     SkAlphaType alphaTypes[] = {
   1081             kUnpremul_SkAlphaType, kPremul_SkAlphaType
   1082     };
   1083     for (SkColorType colorType : colorTypesWithAlpha) {
   1084         for (SkAlphaType alphaType : alphaTypes) {
   1085             // Set color space to nullptr because color correct premultiplies do not round trip.
   1086             SkImageInfo newInfo = codec->getInfo().makeColorType(colorType)
   1087                                                   .makeAlphaType(alphaType)
   1088                                                   .makeColorSpace(nullptr);
   1089             check_round_trip(r, codec.get(), newInfo);
   1090         }
   1091     }
   1092 
   1093     codec = SkCodec::MakeFromStream(GetResourceAsStream("images/index8.png"));
   1094 
   1095     for (SkAlphaType alphaType : alphaTypes) {
   1096         SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType)
   1097                                               .makeColorSpace(nullptr);
   1098         check_round_trip(r, codec.get(), newInfo);
   1099     }
   1100 }
   1101 
   1102 static void test_conversion_possible(skiatest::Reporter* r, const char* path,
   1103                                      bool supportsScanlineDecoder,
   1104                                      bool supportsIncrementalDecoder) {
   1105     std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
   1106     if (!stream) {
   1107         return;
   1108     }
   1109 
   1110     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
   1111     if (!codec) {
   1112         ERRORF(r, "failed to create a codec for %s", path);
   1113         return;
   1114     }
   1115 
   1116     SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType);
   1117 
   1118     SkBitmap bm;
   1119     bm.allocPixels(infoF16);
   1120     SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes());
   1121     REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
   1122 
   1123     result = codec->startScanlineDecode(infoF16);
   1124     if (supportsScanlineDecoder) {
   1125         REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
   1126     } else {
   1127         REPORTER_ASSERT(r, SkCodec::kUnimplemented == result
   1128                         || SkCodec::kInvalidConversion == result);
   1129     }
   1130 
   1131     result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes());
   1132     if (supportsIncrementalDecoder) {
   1133         REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
   1134     } else {
   1135         REPORTER_ASSERT(r, SkCodec::kUnimplemented == result
   1136                         || SkCodec::kInvalidConversion == result);
   1137     }
   1138 
   1139     infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma());
   1140     result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes());
   1141     REPORTER_ASSERT(r, SkCodec::kSuccess == result);
   1142     result = codec->startScanlineDecode(infoF16);
   1143     if (supportsScanlineDecoder) {
   1144         REPORTER_ASSERT(r, SkCodec::kSuccess == result);
   1145     } else {
   1146         REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
   1147     }
   1148 
   1149     result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes());
   1150     if (supportsIncrementalDecoder) {
   1151         REPORTER_ASSERT(r, SkCodec::kSuccess == result);
   1152     } else {
   1153         REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
   1154     }
   1155 }
   1156 
   1157 DEF_TEST(Codec_F16ConversionPossible, r) {
   1158     test_conversion_possible(r, "images/color_wheel.webp", false, false);
   1159     test_conversion_possible(r, "images/mandrill_512_q075.jpg", true, false);
   1160     test_conversion_possible(r, "images/yellow_rose.png", false, true);
   1161 }
   1162 
   1163 static void decode_frame(skiatest::Reporter* r, SkCodec* codec, size_t frame) {
   1164     SkBitmap bm;
   1165     auto info = codec->getInfo().makeColorType(kN32_SkColorType);
   1166     bm.allocPixels(info);
   1167 
   1168     SkCodec::Options opts;
   1169     opts.fFrameIndex = frame;
   1170     REPORTER_ASSERT(r, SkCodec::kSuccess == codec->getPixels(info,
   1171             bm.getPixels(), bm.rowBytes(), &opts));
   1172 }
   1173 
   1174 // For an animated GIF, we should only read enough to decode frame 0 if the
   1175 // client never calls getFrameInfo and only decodes frame 0.
   1176 DEF_TEST(Codec_skipFullParse, r) {
   1177     auto path = "images/test640x479.gif";
   1178     auto streamObj = GetResourceAsStream(path);
   1179     if (!streamObj) {
   1180         return;
   1181     }
   1182     SkStream* stream = streamObj.get();
   1183 
   1184     // Note that we cheat and hold on to the stream pointer, but SkCodec will
   1185     // take ownership. We will not refer to the stream after the SkCodec
   1186     // deletes it.
   1187     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(streamObj)));
   1188     if (!codec) {
   1189         ERRORF(r, "Failed to create codec for %s", path);
   1190         return;
   1191     }
   1192 
   1193     REPORTER_ASSERT(r, stream->hasPosition());
   1194     const size_t sizePosition = stream->getPosition();
   1195     REPORTER_ASSERT(r, stream->hasLength() && sizePosition < stream->getLength());
   1196 
   1197     // This should read more of the stream, but not the whole stream.
   1198     decode_frame(r, codec.get(), 0);
   1199     const size_t positionAfterFirstFrame = stream->getPosition();
   1200     REPORTER_ASSERT(r, positionAfterFirstFrame > sizePosition
   1201                        && positionAfterFirstFrame < stream->getLength());
   1202 
   1203     // There is more data in the stream.
   1204     auto frameInfo = codec->getFrameInfo();
   1205     REPORTER_ASSERT(r, frameInfo.size() == 4);
   1206     REPORTER_ASSERT(r, stream->getPosition() > positionAfterFirstFrame);
   1207 }
   1208 
   1209 // Only rewinds up to a limit.
   1210 class LimitedRewindingStream : public SkStream {
   1211 public:
   1212     static std::unique_ptr<SkStream> Make(const char path[], size_t limit) {
   1213         auto stream = GetResourceAsStream(path);
   1214         if (!stream) {
   1215             return nullptr;
   1216         }
   1217         return std::unique_ptr<SkStream>(new LimitedRewindingStream(std::move(stream), limit));
   1218     }
   1219 
   1220     size_t read(void* buffer, size_t size) override {
   1221         const size_t bytes = fStream->read(buffer, size);
   1222         fPosition += bytes;
   1223         return bytes;
   1224     }
   1225 
   1226     bool isAtEnd() const override {
   1227         return fStream->isAtEnd();
   1228     }
   1229 
   1230     bool rewind() override {
   1231         if (fPosition <= fLimit && fStream->rewind()) {
   1232             fPosition = 0;
   1233             return true;
   1234         }
   1235 
   1236         return false;
   1237     }
   1238 
   1239 private:
   1240     std::unique_ptr<SkStream> fStream;
   1241     const size_t              fLimit;
   1242     size_t                    fPosition;
   1243 
   1244     LimitedRewindingStream(std::unique_ptr<SkStream> stream, size_t limit)
   1245         : fStream(std::move(stream))
   1246         , fLimit(limit)
   1247         , fPosition(0)
   1248     {
   1249         SkASSERT(fStream);
   1250     }
   1251 };
   1252 
   1253 DEF_TEST(Codec_fallBack, r) {
   1254     // SkAndroidCodec needs to be able to fall back to scanline decoding
   1255     // if incremental decoding does not work. Make sure this does not
   1256     // require a rewind.
   1257 
   1258     // Formats that currently do not support incremental decoding
   1259     auto files = {
   1260             "images/CMYK.jpg",
   1261             "images/color_wheel.ico",
   1262             "images/mandrill.wbmp",
   1263             "images/randPixels.bmp",
   1264             };
   1265     for (auto file : files) {
   1266         auto stream = LimitedRewindingStream::Make(file, SkCodec::MinBufferedBytesNeeded());
   1267         if (!stream) {
   1268             SkDebugf("Missing resources (%s). Set --resourcePath.\n", file);
   1269             return;
   1270         }
   1271 
   1272         std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
   1273         if (!codec) {
   1274             ERRORF(r, "Failed to create codec for %s,", file);
   1275             continue;
   1276         }
   1277 
   1278         SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
   1279         SkBitmap bm;
   1280         bm.allocPixels(info);
   1281 
   1282         if (SkCodec::kUnimplemented != codec->startIncrementalDecode(info, bm.getPixels(),
   1283                 bm.rowBytes())) {
   1284             ERRORF(r, "Is scanline decoding now implemented for %s?", file);
   1285             continue;
   1286         }
   1287 
   1288         // Scanline decoding should not require a rewind.
   1289         SkCodec::Result result = codec->startScanlineDecode(info);
   1290         if (SkCodec::kSuccess != result) {
   1291             ERRORF(r, "Scanline decoding failed for %s with %i", file, result);
   1292         }
   1293     }
   1294 }
   1295 
   1296 // This test verifies that we fixed an assert statement that fired when reusing a png codec
   1297 // after scaling.
   1298 DEF_TEST(Codec_reusePng, r) {
   1299     std::unique_ptr<SkStream> stream(GetResourceAsStream("images/plane.png"));
   1300     if (!stream) {
   1301         return;
   1302     }
   1303 
   1304     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(std::move(stream)));
   1305     if (!codec) {
   1306         ERRORF(r, "Failed to create codec\n");
   1307         return;
   1308     }
   1309 
   1310     SkAndroidCodec::AndroidOptions opts;
   1311     opts.fSampleSize = 5;
   1312     auto size = codec->getSampledDimensions(opts.fSampleSize);
   1313     auto info = codec->getInfo().makeWH(size.fWidth, size.fHeight).makeColorType(kN32_SkColorType);
   1314     SkBitmap bm;
   1315     bm.allocPixels(info);
   1316     auto result = codec->getAndroidPixels(info, bm.getPixels(), bm.rowBytes(), &opts);
   1317     REPORTER_ASSERT(r, result == SkCodec::kSuccess);
   1318 
   1319     info = codec->getInfo().makeColorType(kN32_SkColorType);
   1320     bm.allocPixels(info);
   1321     opts.fSampleSize = 1;
   1322     result = codec->getAndroidPixels(info, bm.getPixels(), bm.rowBytes(), &opts);
   1323     REPORTER_ASSERT(r, result == SkCodec::kSuccess);
   1324 }
   1325 
   1326 DEF_TEST(Codec_rowsDecoded, r) {
   1327     auto file = "images/plane_interlaced.png";
   1328     std::unique_ptr<SkStream> stream(GetResourceAsStream(file));
   1329     if (!stream) {
   1330         return;
   1331     }
   1332 
   1333     // This is enough to read the header etc, but no rows.
   1334     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(SkData::MakeFromStream(stream.get(), 99)));
   1335     if (!codec) {
   1336         ERRORF(r, "Failed to create codec\n");
   1337         return;
   1338     }
   1339 
   1340     auto info = codec->getInfo().makeColorType(kN32_SkColorType);
   1341     SkBitmap bm;
   1342     bm.allocPixels(info);
   1343     auto result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
   1344     REPORTER_ASSERT(r, result == SkCodec::kSuccess);
   1345 
   1346     // This is an arbitrary value. The important fact is that it is not zero, and rowsDecoded
   1347     // should get set to zero by incrementalDecode.
   1348     int rowsDecoded = 77;
   1349     result = codec->incrementalDecode(&rowsDecoded);
   1350     REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput);
   1351     REPORTER_ASSERT(r, rowsDecoded == 0);
   1352 }
   1353 
   1354 static void test_invalid_images(skiatest::Reporter* r, const char* path,
   1355                                 SkCodec::Result expectedResult) {
   1356     auto stream = GetResourceAsStream(path);
   1357     if (!stream) {
   1358         return;
   1359     }
   1360 
   1361     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
   1362     REPORTER_ASSERT(r, codec);
   1363 
   1364     test_info(r, codec.get(), codec->getInfo().makeColorType(kN32_SkColorType), expectedResult,
   1365               nullptr);
   1366 }
   1367 
   1368 DEF_TEST(Codec_InvalidImages, r) {
   1369     // ASAN will complain if there is an issue.
   1370     test_invalid_images(r, "invalid_images/skbug5887.gif", SkCodec::kErrorInInput);
   1371     test_invalid_images(r, "invalid_images/many-progressive-scans.jpg", SkCodec::kInvalidInput);
   1372     test_invalid_images(r, "invalid_images/b33251605.bmp", SkCodec::kIncompleteInput);
   1373     test_invalid_images(r, "invalid_images/bad_palette.png", SkCodec::kInvalidInput);
   1374 }
   1375 
   1376 static void test_invalid_header(skiatest::Reporter* r, const char* path) {
   1377     auto data = GetResourceAsData(path);
   1378     if (!data) {
   1379         return;
   1380     }
   1381     std::unique_ptr<SkStreamAsset> stream(new SkMemoryStream(std::move(data)));
   1382     if (!stream) {
   1383         return;
   1384     }
   1385     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
   1386     REPORTER_ASSERT(r, !codec);
   1387 }
   1388 
   1389 DEF_TEST(Codec_InvalidHeader, r) {
   1390     test_invalid_header(r, "invalid_images/int_overflow.ico");
   1391 
   1392     // These files report values that have caused problems with SkFILEStreams.
   1393     // They are invalid, and should not create SkCodecs.
   1394     test_invalid_header(r, "invalid_images/b33651913.bmp");
   1395     test_invalid_header(r, "invalid_images/b34778578.bmp");
   1396 }
   1397 
   1398 DEF_TEST(Codec_InvalidAnimated, r) {
   1399     // ASAN will complain if there is an issue.
   1400     auto path = "invalid_images/skbug6046.gif";
   1401     auto stream = GetResourceAsStream(path);
   1402     if (!stream) {
   1403         return;
   1404     }
   1405 
   1406     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
   1407     REPORTER_ASSERT(r, codec);
   1408     if (!codec) {
   1409         return;
   1410     }
   1411 
   1412     const auto info = codec->getInfo().makeColorType(kN32_SkColorType);
   1413     SkBitmap bm;
   1414     bm.allocPixels(info);
   1415 
   1416     auto frameInfos = codec->getFrameInfo();
   1417     SkCodec::Options opts;
   1418     for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) {
   1419         opts.fFrameIndex = i;
   1420         const auto reqFrame = frameInfos[i].fRequiredFrame;
   1421         opts.fPriorFrame = reqFrame == i - 1 ? reqFrame : SkCodec::kNone;
   1422         auto result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes(), &opts);
   1423         if (result != SkCodec::kSuccess) {
   1424             ERRORF(r, "Failed to start decoding frame %i (out of %i) with error %i\n", i,
   1425                    frameInfos.size(), result);
   1426             continue;
   1427         }
   1428 
   1429         codec->incrementalDecode();
   1430     }
   1431 }
   1432 
   1433 static void encode_format(SkDynamicMemoryWStream* stream, const SkPixmap& pixmap,
   1434                           SkTransferFunctionBehavior unpremulBehavior,
   1435                           SkEncodedImageFormat format) {
   1436     SkPngEncoder::Options pngOptions;
   1437     SkWebpEncoder::Options webpOptions;
   1438     pngOptions.fUnpremulBehavior = unpremulBehavior;
   1439     webpOptions.fUnpremulBehavior = unpremulBehavior;
   1440     switch (format) {
   1441         case SkEncodedImageFormat::kPNG:
   1442             SkPngEncoder::Encode(stream, pixmap, pngOptions);
   1443             break;
   1444         case SkEncodedImageFormat::kJPEG:
   1445             SkJpegEncoder::Encode(stream, pixmap, SkJpegEncoder::Options());
   1446             break;
   1447         case SkEncodedImageFormat::kWEBP:
   1448             SkWebpEncoder::Encode(stream, pixmap, webpOptions);
   1449             break;
   1450         default:
   1451             SkASSERT(false);
   1452             break;
   1453     }
   1454 }
   1455 
   1456 static void test_encode_icc(skiatest::Reporter* r, SkEncodedImageFormat format,
   1457                             SkTransferFunctionBehavior unpremulBehavior) {
   1458     // Test with sRGB color space.
   1459     SkBitmap srgbBitmap;
   1460     SkImageInfo srgbInfo = SkImageInfo::MakeS32(1, 1, kOpaque_SkAlphaType);
   1461     srgbBitmap.allocPixels(srgbInfo);
   1462     *srgbBitmap.getAddr32(0, 0) = 0;
   1463     SkPixmap pixmap;
   1464     srgbBitmap.peekPixels(&pixmap);
   1465     SkDynamicMemoryWStream srgbBuf;
   1466     encode_format(&srgbBuf, pixmap, unpremulBehavior, format);
   1467     sk_sp<SkData> srgbData = srgbBuf.detachAsData();
   1468     std::unique_ptr<SkCodec> srgbCodec(SkCodec::MakeFromData(srgbData));
   1469     REPORTER_ASSERT(r, srgbCodec->getInfo().colorSpace() == SkColorSpace::MakeSRGB().get());
   1470 
   1471     // Test with P3 color space.
   1472     SkDynamicMemoryWStream p3Buf;
   1473     sk_sp<SkColorSpace> p3 = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
   1474                                                    SkColorSpace::kDCIP3_D65_Gamut);
   1475     pixmap.setColorSpace(p3);
   1476     encode_format(&p3Buf, pixmap, unpremulBehavior, format);
   1477     sk_sp<SkData> p3Data = p3Buf.detachAsData();
   1478     std::unique_ptr<SkCodec> p3Codec(SkCodec::MakeFromData(p3Data));
   1479     REPORTER_ASSERT(r, p3Codec->getInfo().colorSpace()->gammaCloseToSRGB());
   1480     SkMatrix44 mat0(SkMatrix44::kUninitialized_Constructor);
   1481     SkMatrix44 mat1(SkMatrix44::kUninitialized_Constructor);
   1482     bool success = p3->toXYZD50(&mat0);
   1483     REPORTER_ASSERT(r, success);
   1484     success = p3Codec->getInfo().colorSpace()->toXYZD50(&mat1);
   1485     REPORTER_ASSERT(r, success);
   1486 
   1487     for (int i = 0; i < 4; i++) {
   1488         for (int j = 0; j < 4; j++) {
   1489             REPORTER_ASSERT(r, color_space_almost_equal(mat0.get(i, j), mat1.get(i, j)));
   1490         }
   1491     }
   1492 }
   1493 
   1494 DEF_TEST(Codec_EncodeICC, r) {
   1495     test_encode_icc(r, SkEncodedImageFormat::kPNG, SkTransferFunctionBehavior::kRespect);
   1496     test_encode_icc(r, SkEncodedImageFormat::kJPEG, SkTransferFunctionBehavior::kRespect);
   1497     test_encode_icc(r, SkEncodedImageFormat::kWEBP, SkTransferFunctionBehavior::kRespect);
   1498     test_encode_icc(r, SkEncodedImageFormat::kPNG, SkTransferFunctionBehavior::kIgnore);
   1499     test_encode_icc(r, SkEncodedImageFormat::kJPEG, SkTransferFunctionBehavior::kIgnore);
   1500     test_encode_icc(r, SkEncodedImageFormat::kWEBP, SkTransferFunctionBehavior::kIgnore);
   1501 }
   1502 
   1503 DEF_TEST(Codec_webp_rowsDecoded, r) {
   1504     const char* path = "images/baby_tux.webp";
   1505     sk_sp<SkData> data(GetResourceAsData(path));
   1506     if (!data) {
   1507         return;
   1508     }
   1509 
   1510     // Truncate this file so that the header is available but no rows can be
   1511     // decoded. This should create a codec but fail to decode.
   1512     size_t truncatedSize = 5000;
   1513     sk_sp<SkData> subset = SkData::MakeSubset(data.get(), 0, truncatedSize);
   1514     std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(std::move(subset));
   1515     if (!codec) {
   1516         ERRORF(r, "Failed to create a codec for %s truncated to only %lu bytes",
   1517                path, truncatedSize);
   1518         return;
   1519     }
   1520 
   1521     test_info(r, codec.get(), codec->getInfo(), SkCodec::kInvalidInput, nullptr);
   1522 }
   1523