Home | History | Annotate | Download | only in codec
      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 "SkCodecPriv.h"
      9 #include "SkColorPriv.h"
     10 #include "SkColorTable.h"
     11 #include "SkBitmap.h"
     12 #include "SkMath.h"
     13 #include "SkOpts.h"
     14 #include "SkPngCodec.h"
     15 #include "SkSize.h"
     16 #include "SkStream.h"
     17 #include "SkSwizzler.h"
     18 #include "SkTemplates.h"
     19 #include "SkUtils.h"
     20 
     21 ///////////////////////////////////////////////////////////////////////////////
     22 // Callback functions
     23 ///////////////////////////////////////////////////////////////////////////////
     24 
     25 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
     26     SkCodecPrintf("------ png error %s\n", msg);
     27     longjmp(png_jmpbuf(png_ptr), 1);
     28 }
     29 
     30 void sk_warning_fn(png_structp, png_const_charp msg) {
     31     SkCodecPrintf("----- png warning %s\n", msg);
     32 }
     33 
     34 static void sk_read_fn(png_structp png_ptr, png_bytep data,
     35                        png_size_t length) {
     36     SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr));
     37     const size_t bytes = stream->read(data, length);
     38     if (bytes != length) {
     39         // FIXME: We want to report the fact that the stream was truncated.
     40         // One way to do that might be to pass a enum to longjmp so setjmp can
     41         // specify the failure.
     42         png_error(png_ptr, "Read Error!");
     43     }
     44 }
     45 
     46 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
     47 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
     48     SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
     49     // readChunk() returning true means continue decoding
     50     return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1;
     51 }
     52 #endif
     53 
     54 ///////////////////////////////////////////////////////////////////////////////
     55 // Helpers
     56 ///////////////////////////////////////////////////////////////////////////////
     57 
     58 class AutoCleanPng : public SkNoncopyable {
     59 public:
     60     AutoCleanPng(png_structp png_ptr)
     61         : fPng_ptr(png_ptr)
     62         , fInfo_ptr(nullptr) {}
     63 
     64     ~AutoCleanPng() {
     65         // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
     66         if (fPng_ptr) {
     67             png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
     68             png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
     69         }
     70     }
     71 
     72     void setInfoPtr(png_infop info_ptr) {
     73         SkASSERT(nullptr == fInfo_ptr);
     74         fInfo_ptr = info_ptr;
     75     }
     76 
     77     void detach() {
     78         fPng_ptr = nullptr;
     79         fInfo_ptr = nullptr;
     80     }
     81 
     82 private:
     83     png_structp     fPng_ptr;
     84     png_infop       fInfo_ptr;
     85 };
     86 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
     87 
     88 // Method for coverting to either an SkPMColor or a similarly packed
     89 // unpremultiplied color.
     90 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
     91 
     92 // Note: SkColorTable claims to store SkPMColors, which is not necessarily
     93 // the case here.
     94 // TODO: If we add support for non-native swizzles, we'll need to handle that here.
     95 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) {
     96 
     97     int numColors;
     98     png_color* palette;
     99     if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
    100         return false;
    101     }
    102 
    103     // Note: These are not necessarily SkPMColors.
    104     SkPMColor colorPtr[256];
    105 
    106     png_bytep alphas;
    107     int numColorsWithAlpha = 0;
    108     if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
    109         // Choose which function to use to create the color table. If the final destination's
    110         // colortype is unpremultiplied, the color table will store unpremultiplied colors.
    111         PackColorProc proc;
    112         if (premultiply) {
    113             proc = &SkPremultiplyARGBInline;
    114         } else {
    115             proc = &SkPackARGB32NoCheck;
    116         }
    117 
    118         for (int i = 0; i < numColorsWithAlpha; i++) {
    119             // We don't have a function in SkOpts that combines a set of alphas with a set
    120             // of RGBs.  We could write one, but it's hardly worth it, given that this
    121             // is such a small fraction of the total decode time.
    122             colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
    123             palette++;
    124         }
    125     }
    126 
    127     if (numColorsWithAlpha < numColors) {
    128         // The optimized code depends on a 3-byte png_color struct with the colors
    129         // in RGB order.  These checks make sure it is safe to use.
    130         static_assert(3 == sizeof(png_color), "png_color struct has changed.  Opts are broken.");
    131 #ifdef SK_DEBUG
    132         SkASSERT(&palette->red < &palette->green);
    133         SkASSERT(&palette->green < &palette->blue);
    134 #endif
    135 
    136 #ifdef SK_PMCOLOR_IS_RGBA
    137         SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha);
    138 #else
    139         SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha);
    140 #endif
    141     }
    142 
    143     // Pad the color table with the last color in the table (or black) in the case that
    144     // invalid pixel indices exceed the number of colors in the table.
    145     const int maxColors = 1 << fBitDepth;
    146     if (numColors < maxColors) {
    147         SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_ColorBLACK;
    148         sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors);
    149     }
    150 
    151     // Set the new color count.
    152     if (ctableCount != nullptr) {
    153         *ctableCount = maxColors;
    154     }
    155 
    156     fColorTable.reset(new SkColorTable(colorPtr, maxColors));
    157     return true;
    158 }
    159 
    160 ///////////////////////////////////////////////////////////////////////////////
    161 // Creation
    162 ///////////////////////////////////////////////////////////////////////////////
    163 
    164 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
    165     return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
    166 }
    167 
    168 // Reads the header and initializes the output fields, if not NULL.
    169 //
    170 // @param stream Input data. Will be read to get enough information to properly
    171 //      setup the codec.
    172 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
    173 //      If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
    174 //      expected to continue to own it for the lifetime of the png_ptr.
    175 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new
    176 //      png_structp on success.
    177 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new
    178 //      png_infop on success;
    179 // @param imageInfo Optional output variable. If non-NULL, will be set to
    180 //      reflect the properties of the encoded image on success.
    181 // @param bitDepthPtr Optional output variable. If non-NULL, will be set to the
    182 //      bit depth of the encoded image on success.
    183 // @param numberPassesPtr Optional output variable. If non-NULL, will be set to
    184 //      the number_passes of the encoded image on success.
    185 // @return true on success, in which case the caller is responsible for calling
    186 //      png_destroy_read_struct(png_ptrp, info_ptrp).
    187 //      If it returns false, the passed in fields (except stream) are unchanged.
    188 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
    189                         png_structp* png_ptrp, png_infop* info_ptrp,
    190                         SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPassesPtr) {
    191     // The image is known to be a PNG. Decode enough to know the SkImageInfo.
    192     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
    193                                                  sk_error_fn, sk_warning_fn);
    194     if (!png_ptr) {
    195         return false;
    196     }
    197 
    198     AutoCleanPng autoClean(png_ptr);
    199 
    200     png_infop info_ptr = png_create_info_struct(png_ptr);
    201     if (info_ptr == nullptr) {
    202         return false;
    203     }
    204 
    205     autoClean.setInfoPtr(info_ptr);
    206 
    207     // FIXME: Could we use the return value of setjmp to specify the type of
    208     // error?
    209     if (setjmp(png_jmpbuf(png_ptr))) {
    210         return false;
    211     }
    212 
    213     png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);
    214 
    215 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
    216     // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
    217     // This needs to be installed before we read the png header.  Android may store ninepatch
    218     // chunks in the header.
    219     if (chunkReader) {
    220         png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
    221         png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
    222     }
    223 #endif
    224 
    225     // The call to png_read_info() gives us all of the information from the
    226     // PNG file before the first IDAT (image data chunk).
    227     png_read_info(png_ptr, info_ptr);
    228     png_uint_32 origWidth, origHeight;
    229     int bitDepth, encodedColorType;
    230     png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
    231                  &encodedColorType, nullptr, nullptr, nullptr);
    232 
    233     if (bitDepthPtr) {
    234         *bitDepthPtr = bitDepth;
    235     }
    236 
    237     // Tell libpng to strip 16 bit/color files down to 8 bits/color.
    238     // TODO: Should we handle this in SkSwizzler?  Could this also benefit
    239     //       RAW decodes?
    240     if (bitDepth == 16) {
    241         SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
    242         png_set_strip_16(png_ptr);
    243     }
    244 
    245     // Now determine the default colorType and alphaType and set the required transforms.
    246     // Often, we depend on SkSwizzler to perform any transforms that we need.  However, we
    247     // still depend on libpng for many of the rare and PNG-specific cases.
    248     SkColorType colorType = kUnknown_SkColorType;
    249     SkAlphaType alphaType = kUnknown_SkAlphaType;
    250     switch (encodedColorType) {
    251         case PNG_COLOR_TYPE_PALETTE:
    252             // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
    253             // byte into separate bytes (useful for paletted and grayscale images).
    254             if (bitDepth < 8) {
    255                 // TODO: Should we use SkSwizzler here?
    256                 png_set_packing(png_ptr);
    257             }
    258 
    259             colorType = kIndex_8_SkColorType;
    260             // Set the alpha type depending on if a transparency chunk exists.
    261             alphaType = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
    262                     kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
    263             break;
    264         case PNG_COLOR_TYPE_RGB:
    265             if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
    266                 // Convert to RGBA if transparency chunk exists.
    267                 png_set_tRNS_to_alpha(png_ptr);
    268                 alphaType = kUnpremul_SkAlphaType;
    269             } else {
    270                 alphaType = kOpaque_SkAlphaType;
    271             }
    272             colorType = kN32_SkColorType;
    273             break;
    274         case PNG_COLOR_TYPE_GRAY:
    275             // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
    276             if (bitDepth < 8) {
    277                 // TODO: Should we use SkSwizzler here?
    278                 png_set_expand_gray_1_2_4_to_8(png_ptr);
    279             }
    280 
    281             if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
    282                 png_set_tRNS_to_alpha(png_ptr);
    283 
    284                 // We will recommend kN32 here since we do not support kGray
    285                 // with alpha.
    286                 colorType = kN32_SkColorType;
    287                 alphaType = kUnpremul_SkAlphaType;
    288             } else {
    289                 colorType = kGray_8_SkColorType;
    290                 alphaType = kOpaque_SkAlphaType;
    291             }
    292             break;
    293         case PNG_COLOR_TYPE_GRAY_ALPHA:
    294             // We will recommend kN32 here since we do not support anything
    295             // similar to GRAY_ALPHA.
    296             colorType = kN32_SkColorType;
    297             alphaType = kUnpremul_SkAlphaType;
    298             break;
    299         case PNG_COLOR_TYPE_RGBA:
    300             colorType = kN32_SkColorType;
    301             alphaType = kUnpremul_SkAlphaType;
    302             break;
    303         default:
    304             // All the color types have been covered above.
    305             SkASSERT(false);
    306     }
    307 
    308     int numberPasses = png_set_interlace_handling(png_ptr);
    309     if (numberPassesPtr) {
    310         *numberPassesPtr = numberPasses;
    311     }
    312 
    313     SkColorProfileType profileType = kLinear_SkColorProfileType;
    314     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
    315         profileType = kSRGB_SkColorProfileType;
    316     }
    317 
    318     if (imageInfo) {
    319         *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaType, profileType);
    320     }
    321     autoClean.detach();
    322     if (png_ptrp) {
    323         *png_ptrp = png_ptr;
    324     }
    325     if (info_ptrp) {
    326         *info_ptrp = info_ptr;
    327     }
    328 
    329     return true;
    330 }
    331 
    332 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkReader* chunkReader,
    333                        png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses)
    334     : INHERITED(info, stream)
    335     , fPngChunkReader(SkSafeRef(chunkReader))
    336     , fPng_ptr(png_ptr)
    337     , fInfo_ptr(info_ptr)
    338     , fSrcConfig(SkSwizzler::kUnknown)
    339     , fNumberPasses(numberPasses)
    340     , fBitDepth(bitDepth)
    341 {}
    342 
    343 SkPngCodec::~SkPngCodec() {
    344     this->destroyReadStruct();
    345 }
    346 
    347 void SkPngCodec::destroyReadStruct() {
    348     if (fPng_ptr) {
    349         // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
    350         SkASSERT(fInfo_ptr);
    351         png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr);
    352         fPng_ptr = nullptr;
    353         fInfo_ptr = nullptr;
    354     }
    355 }
    356 
    357 ///////////////////////////////////////////////////////////////////////////////
    358 // Getting the pixels
    359 ///////////////////////////////////////////////////////////////////////////////
    360 
    361 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
    362                                                const Options& options,
    363                                                SkPMColor ctable[],
    364                                                int* ctableCount) {
    365     // FIXME: Could we use the return value of setjmp to specify the type of
    366     // error?
    367     if (setjmp(png_jmpbuf(fPng_ptr))) {
    368         SkCodecPrintf("setjmp long jump!\n");
    369         return kInvalidInput;
    370     }
    371     png_read_update_info(fPng_ptr, fInfo_ptr);
    372 
    373     // suggestedColorType was determined in read_header() based on the encodedColorType
    374     const SkColorType suggestedColorType = this->getInfo().colorType();
    375 
    376     switch (suggestedColorType) {
    377         case kIndex_8_SkColorType:
    378             //decode palette to Skia format
    379             fSrcConfig = SkSwizzler::kIndex;
    380             if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(),
    381                     ctableCount)) {
    382                 return kInvalidInput;
    383             }
    384             break;
    385         case kGray_8_SkColorType:
    386             fSrcConfig = SkSwizzler::kGray;
    387             break;
    388         case kN32_SkColorType: {
    389             const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_ptr);
    390             if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType ||
    391                     PNG_COLOR_TYPE_GRAY == encodedColorType) {
    392                 // If encodedColorType is GRAY, there must be a transparent chunk.
    393                 // Otherwise, suggestedColorType would be kGray.  We have already
    394                 // instructed libpng to convert the transparent chunk to alpha,
    395                 // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha.
    396                 SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA ||
    397                         png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS));
    398 
    399                 fSrcConfig = SkSwizzler::kGrayAlpha;
    400             } else {
    401                 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
    402                     fSrcConfig = SkSwizzler::kRGB;
    403                 } else {
    404                     fSrcConfig = SkSwizzler::kRGBA;
    405                 }
    406             }
    407             break;
    408         }
    409         default:
    410             // We will always recommend one of the above colorTypes.
    411             SkASSERT(false);
    412     }
    413 
    414     // Copy the color table to the client if they request kIndex8 mode
    415     copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
    416 
    417     // Create the swizzler.  SkPngCodec retains ownership of the color table.
    418     const SkPMColor* colors = get_color_ptr(fColorTable.get());
    419     fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, options));
    420     SkASSERT(fSwizzler);
    421 
    422     return kSuccess;
    423 }
    424 
    425 
    426 bool SkPngCodec::onRewind() {
    427     // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
    428     // succeeds, they will be repopulated, and if it fails, they will
    429     // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
    430     // come through this function which will rewind and again attempt
    431     // to reinitialize them.
    432     this->destroyReadStruct();
    433 
    434     png_structp png_ptr;
    435     png_infop info_ptr;
    436     if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr,
    437                      nullptr, nullptr, nullptr)) {
    438         return false;
    439     }
    440 
    441     fPng_ptr = png_ptr;
    442     fInfo_ptr = info_ptr;
    443     return true;
    444 }
    445 
    446 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
    447                                         size_t dstRowBytes, const Options& options,
    448                                         SkPMColor ctable[], int* ctableCount,
    449                                         int* rowsDecoded) {
    450     if (!conversion_possible(requestedInfo, this->getInfo())) {
    451         return kInvalidConversion;
    452     }
    453     if (options.fSubset) {
    454         // Subsets are not supported.
    455         return kUnimplemented;
    456     }
    457 
    458     // Note that ctable and ctableCount may be modified if there is a color table
    459     const Result result = this->initializeSwizzler(requestedInfo, options, ctable, ctableCount);
    460     if (result != kSuccess) {
    461         return result;
    462     }
    463 
    464     const int width = requestedInfo.width();
    465     const int height = requestedInfo.height();
    466     const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
    467     const size_t srcRowBytes = width * bpp;
    468 
    469     // FIXME: Could we use the return value of setjmp to specify the type of
    470     // error?
    471     int row = 0;
    472     // This must be declared above the call to setjmp to avoid memory leaks on incomplete images.
    473     SkAutoTMalloc<uint8_t> storage;
    474     if (setjmp(png_jmpbuf(fPng_ptr))) {
    475         // Assume that any error that occurs while reading rows is caused by an incomplete input.
    476         if (fNumberPasses > 1) {
    477             // FIXME (msarett): Handle incomplete interlaced pngs.
    478             return (row == height) ? kSuccess : kInvalidInput;
    479         }
    480         // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium,
    481         // Ubuntu Image Viewer).  This is because we use the default buffer size in libpng (8192
    482         // bytes), and if we can't fill the buffer, we immediately fail.
    483         // For example, if we try to read 8192 bytes, and the image (incorrectly) only contains
    484         // half that, which may have been enough to contain a non-zero number of lines, we fail
    485         // when we could have decoded a few more lines and then failed.
    486         // The read function that we provide for libpng has no way of indicating that we have
    487         // made a partial read.
    488         // Making our buffer size smaller improves our incomplete decodes, but what impact does
    489         // it have on regular decode performance?  Should we investigate using a different API
    490         // instead of png_read_row?  Chromium uses png_process_data.
    491         *rowsDecoded = row;
    492         return (row == height) ? kSuccess : kIncompleteInput;
    493     }
    494 
    495     // FIXME: We could split these out based on subclass.
    496     void* dstRow = dst;
    497     if (fNumberPasses > 1) {
    498         storage.reset(height * srcRowBytes);
    499         uint8_t* const base = storage.get();
    500 
    501         for (int i = 0; i < fNumberPasses; i++) {
    502             uint8_t* srcRow = base;
    503             for (int y = 0; y < height; y++) {
    504                 png_read_row(fPng_ptr, srcRow, nullptr);
    505                 srcRow += srcRowBytes;
    506             }
    507         }
    508 
    509         // Now swizzle it.
    510         uint8_t* srcRow = base;
    511         for (; row < height; row++) {
    512             fSwizzler->swizzle(dstRow, srcRow);
    513             dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    514             srcRow += srcRowBytes;
    515         }
    516     } else {
    517         storage.reset(srcRowBytes);
    518         uint8_t* srcRow = storage.get();
    519         for (; row < height; row++) {
    520             png_read_row(fPng_ptr, srcRow, nullptr);
    521             fSwizzler->swizzle(dstRow, srcRow);
    522             dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    523         }
    524     }
    525 
    526     // read rest of file, and get additional comment and time chunks in info_ptr
    527     png_read_end(fPng_ptr, fInfo_ptr);
    528 
    529     return kSuccess;
    530 }
    531 
    532 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const {
    533     const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
    534     if (colorPtr) {
    535         return get_color_table_fill_value(colorType, colorPtr, 0);
    536     }
    537     return INHERITED::onGetFillValue(colorType);
    538 }
    539 
    540 // Subclass of SkPngCodec which supports scanline decoding
    541 class SkPngScanlineDecoder : public SkPngCodec {
    542 public:
    543     SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
    544             SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
    545         : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1)
    546         , fSrcRow(nullptr)
    547     {}
    548 
    549     Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
    550             SkPMColor ctable[], int* ctableCount) override {
    551         if (!conversion_possible(dstInfo, this->getInfo())) {
    552             return kInvalidConversion;
    553         }
    554 
    555         const Result result = this->initializeSwizzler(dstInfo, options, ctable,
    556                                                        ctableCount);
    557         if (result != kSuccess) {
    558             return result;
    559         }
    560 
    561         fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig()));
    562         fSrcRow = fStorage.get();
    563 
    564         return kSuccess;
    565     }
    566 
    567     int onGetScanlines(void* dst, int count, size_t rowBytes) override {
    568         // Assume that an error in libpng indicates an incomplete input.
    569         int row = 0;
    570         if (setjmp(png_jmpbuf(this->png_ptr()))) {
    571             SkCodecPrintf("setjmp long jump!\n");
    572             return row;
    573         }
    574 
    575         void* dstRow = dst;
    576         for (; row < count; row++) {
    577             png_read_row(this->png_ptr(), fSrcRow, nullptr);
    578             this->swizzler()->swizzle(dstRow, fSrcRow);
    579             dstRow = SkTAddOffset<void>(dstRow, rowBytes);
    580         }
    581 
    582         return row;
    583     }
    584 
    585     bool onSkipScanlines(int count) override {
    586         // Assume that an error in libpng indicates an incomplete input.
    587         if (setjmp(png_jmpbuf(this->png_ptr()))) {
    588             SkCodecPrintf("setjmp long jump!\n");
    589             return false;
    590         }
    591 
    592         for (int row = 0; row < count; row++) {
    593             png_read_row(this->png_ptr(), fSrcRow, nullptr);
    594         }
    595         return true;
    596     }
    597 
    598 private:
    599     SkAutoTMalloc<uint8_t>      fStorage;
    600     uint8_t*                    fSrcRow;
    601 
    602     typedef SkPngCodec INHERITED;
    603 };
    604 
    605 
    606 class SkPngInterlacedScanlineDecoder : public SkPngCodec {
    607 public:
    608     SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
    609             SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr,
    610             int bitDepth, int numberPasses)
    611         : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses)
    612         , fHeight(-1)
    613         , fCanSkipRewind(false)
    614     {
    615         SkASSERT(numberPasses != 1);
    616     }
    617 
    618     Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
    619             SkPMColor ctable[], int* ctableCount) override {
    620         if (!conversion_possible(dstInfo, this->getInfo())) {
    621             return kInvalidConversion;
    622         }
    623 
    624         const Result result = this->initializeSwizzler(dstInfo, options, ctable,
    625                                                        ctableCount);
    626         if (result != kSuccess) {
    627             return result;
    628         }
    629 
    630         fHeight = dstInfo.height();
    631         // FIXME: This need not be called on a second call to onStartScanlineDecode.
    632         fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig());
    633         fGarbageRow.reset(fSrcRowBytes);
    634         fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
    635         fCanSkipRewind = true;
    636 
    637         return SkCodec::kSuccess;
    638     }
    639 
    640     int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
    641         // rewind stream if have previously called onGetScanlines,
    642         // since we need entire progressive image to get scanlines
    643         if (fCanSkipRewind) {
    644             // We already rewound in onStartScanlineDecode, so there is no reason to rewind.
    645             // Next time onGetScanlines is called, we will need to rewind.
    646             fCanSkipRewind = false;
    647         } else {
    648             // rewindIfNeeded resets fCurrScanline, since it assumes that start
    649             // needs to be called again before scanline decoding. PNG scanline
    650             // decoding is the exception, since it needs to rewind between
    651             // calls to getScanlines. Keep track of fCurrScanline, to undo the
    652             // reset.
    653             const int currScanline = this->nextScanline();
    654             // This method would never be called if currScanline is -1
    655             SkASSERT(currScanline != -1);
    656 
    657             if (!this->rewindIfNeeded()) {
    658                 return kCouldNotRewind;
    659             }
    660             this->updateCurrScanline(currScanline);
    661         }
    662 
    663         if (setjmp(png_jmpbuf(this->png_ptr()))) {
    664             SkCodecPrintf("setjmp long jump!\n");
    665             // FIXME (msarett): Returning 0 is pessimistic.  If we can complete a single pass,
    666             // we may be able to report that all of the memory has been initialized.  Even if we
    667             // fail on the first pass, we can still report than some scanlines are initialized.
    668             return 0;
    669         }
    670         SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
    671         uint8_t* storagePtr = storage.get();
    672         uint8_t* srcRow;
    673         const int startRow = this->nextScanline();
    674         for (int i = 0; i < this->numberPasses(); i++) {
    675             // read rows we planned to skip into garbage row
    676             for (int y = 0; y < startRow; y++){
    677                 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
    678             }
    679             // read rows we care about into buffer
    680             srcRow = storagePtr;
    681             for (int y = 0; y < count; y++) {
    682                 png_read_row(this->png_ptr(), srcRow, nullptr);
    683                 srcRow += fSrcRowBytes;
    684             }
    685             // read rows we don't want into garbage buffer
    686             for (int y = 0; y < fHeight - startRow - count; y++) {
    687                 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
    688             }
    689         }
    690         //swizzle the rows we care about
    691         srcRow = storagePtr;
    692         void* dstRow = dst;
    693         for (int y = 0; y < count; y++) {
    694             this->swizzler()->swizzle(dstRow, srcRow);
    695             dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    696             srcRow += fSrcRowBytes;
    697         }
    698 
    699         return count;
    700     }
    701 
    702     bool onSkipScanlines(int count) override {
    703         // The non-virtual version will update fCurrScanline.
    704         return true;
    705     }
    706 
    707     SkScanlineOrder onGetScanlineOrder() const override {
    708         return kNone_SkScanlineOrder;
    709     }
    710 
    711 private:
    712     int                         fHeight;
    713     size_t                      fSrcRowBytes;
    714     SkAutoMalloc                fGarbageRow;
    715     uint8_t*                    fGarbageRowPtr;
    716     // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
    717     // is called whenever some action is taken that reads the stream and
    718     // therefore the next call will require a rewind. So it modifies a boolean
    719     // to note that the *next* time it is called a rewind is needed.
    720     // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
    721     // onStartScanlineDecode followed by onGetScanlines does *not* require a
    722     // rewind. Since rewindIfNeeded does not have this flexibility, we need to
    723     // add another layer.
    724     bool                        fCanSkipRewind;
    725 
    726     typedef SkPngCodec INHERITED;
    727 };
    728 
    729 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
    730     SkAutoTDelete<SkStream> streamDeleter(stream);
    731     png_structp png_ptr;
    732     png_infop info_ptr;
    733     SkImageInfo imageInfo;
    734     int bitDepth;
    735     int numberPasses;
    736 
    737     if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitDepth,
    738                      &numberPasses)) {
    739         return nullptr;
    740     }
    741 
    742     if (1 == numberPasses) {
    743         return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
    744                                         png_ptr, info_ptr, bitDepth);
    745     }
    746 
    747     return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
    748                                               png_ptr, info_ptr, bitDepth, numberPasses);
    749 }
    750