xref: /third_party/skia/src/codec/SkPngCodec.cpp (revision cb93a386)
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 "include/core/SkBitmap.h"
9#include "include/core/SkColorSpace.h"
10#include "include/core/SkMath.h"
11#include "include/core/SkPoint3.h"
12#include "include/core/SkSize.h"
13#include "include/core/SkStream.h"
14#include "include/private/SkColorData.h"
15#include "include/private/SkMacros.h"
16#include "include/private/SkTemplates.h"
17#include "src/codec/SkCodecPriv.h"
18#include "src/codec/SkColorTable.h"
19#include "src/codec/SkPngCodec.h"
20#include "src/codec/SkPngPriv.h"
21#include "src/codec/SkSwizzler.h"
22#include "src/core/SkOpts.h"
23
24#include "png.h"
25#include <algorithm>
26
27#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
28    #include "include/android/SkAndroidFrameworkUtils.h"
29#endif
30
31// This warning triggers false postives way too often in here.
32#if defined(__GNUC__) && !defined(__clang__)
33    #pragma GCC diagnostic ignored "-Wclobbered"
34#endif
35
36// FIXME (scroggo): We can use png_jumpbuf directly once Google3 is on 1.6
37#define PNG_JMPBUF(x) png_jmpbuf((png_structp) x)
38
39///////////////////////////////////////////////////////////////////////////////
40// Callback functions
41///////////////////////////////////////////////////////////////////////////////
42
43// When setjmp is first called, it returns 0, meaning longjmp was not called.
44constexpr int kSetJmpOkay   = 0;
45// An error internal to libpng.
46constexpr int kPngError     = 1;
47// Passed to longjmp when we have decoded as many lines as we need.
48constexpr int kStopDecoding = 2;
49
50static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
51    SkCodecPrintf("------ png error %s\n", msg);
52    longjmp(PNG_JMPBUF(png_ptr), kPngError);
53}
54
55void sk_warning_fn(png_structp, png_const_charp msg) {
56    SkCodecPrintf("----- png warning %s\n", msg);
57}
58
59#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
60static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
61    SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
62    // readChunk() returning true means continue decoding
63    return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1;
64}
65#endif
66
67///////////////////////////////////////////////////////////////////////////////
68// Helpers
69///////////////////////////////////////////////////////////////////////////////
70
71class AutoCleanPng : public SkNoncopyable {
72public:
73    /*
74     *  This class does not take ownership of stream or reader, but if codecPtr
75     *  is non-NULL, and decodeBounds succeeds, it will have created a new
76     *  SkCodec (pointed to by *codecPtr) which will own/ref them, as well as
77     *  the png_ptr and info_ptr.
78     */
79    AutoCleanPng(png_structp png_ptr, SkStream* stream, SkPngChunkReader* reader,
80            SkCodec** codecPtr)
81        : fPng_ptr(png_ptr)
82        , fInfo_ptr(nullptr)
83        , fStream(stream)
84        , fChunkReader(reader)
85        , fOutCodec(codecPtr)
86    {}
87
88    ~AutoCleanPng() {
89        // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
90        if (fPng_ptr) {
91            png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
92            png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
93        }
94    }
95
96    void setInfoPtr(png_infop info_ptr) {
97        SkASSERT(nullptr == fInfo_ptr);
98        fInfo_ptr = info_ptr;
99    }
100
101    /**
102     *  Reads enough of the input stream to decode the bounds.
103     *  @return false if the stream is not a valid PNG (or too short).
104     *          true if it read enough of the stream to determine the bounds.
105     *          In the latter case, the stream may have been read beyond the
106     *          point to determine the bounds, and the png_ptr will have saved
107     *          any extra data. Further, if the codecPtr supplied to the
108     *          constructor was not NULL, it will now point to a new SkCodec,
109     *          which owns (or refs, in the case of the SkPngChunkReader) the
110     *          inputs. If codecPtr was NULL, the png_ptr and info_ptr are
111     *          unowned, and it is up to the caller to destroy them.
112     */
113    bool decodeBounds();
114
115private:
116    png_structp         fPng_ptr;
117    png_infop           fInfo_ptr;
118    SkStream*           fStream;
119    SkPngChunkReader*   fChunkReader;
120    SkCodec**           fOutCodec;
121
122    void infoCallback(size_t idatLength);
123
124    void releasePngPtrs() {
125        fPng_ptr = nullptr;
126        fInfo_ptr = nullptr;
127    }
128};
129
130static inline bool is_chunk(const png_byte* chunk, const char* tag) {
131    return memcmp(chunk + 4, tag, 4) == 0;
132}
133
134static inline bool process_data(png_structp png_ptr, png_infop info_ptr,
135        SkStream* stream, void* buffer, size_t bufferSize, size_t length) {
136    while (length > 0) {
137        const size_t bytesToProcess = std::min(bufferSize, length);
138        const size_t bytesRead = stream->read(buffer, bytesToProcess);
139        png_process_data(png_ptr, info_ptr, (png_bytep) buffer, bytesRead);
140        if (bytesRead < bytesToProcess) {
141            return false;
142        }
143        length -= bytesToProcess;
144    }
145    return true;
146}
147
148bool AutoCleanPng::decodeBounds() {
149    if (setjmp(PNG_JMPBUF(fPng_ptr))) {
150        return false;
151    }
152
153    png_set_progressive_read_fn(fPng_ptr, nullptr, nullptr, nullptr, nullptr);
154
155    // Arbitrary buffer size, though note that it matches (below)
156    // SkPngCodec::processData(). FIXME: Can we better suit this to the size of
157    // the PNG header?
158    constexpr size_t kBufferSize = 4096;
159    char buffer[kBufferSize];
160
161    {
162        // Parse the signature.
163        if (fStream->read(buffer, 8) < 8) {
164            return false;
165        }
166
167        png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, 8);
168    }
169
170    while (true) {
171        // Parse chunk length and type.
172        if (fStream->read(buffer, 8) < 8) {
173            // We have read to the end of the input without decoding bounds.
174            break;
175        }
176
177        png_byte* chunk = reinterpret_cast<png_byte*>(buffer);
178        const size_t length = png_get_uint_32(chunk);
179
180        if (is_chunk(chunk, "IDAT")) {
181            this->infoCallback(length);
182            return true;
183        }
184
185        png_process_data(fPng_ptr, fInfo_ptr, chunk, 8);
186        // Process the full chunk + CRC.
187        if (!process_data(fPng_ptr, fInfo_ptr, fStream, buffer, kBufferSize, length + 4)) {
188            return false;
189        }
190    }
191
192    return false;
193}
194
195bool SkPngCodec::processData() {
196    switch (setjmp(PNG_JMPBUF(fPng_ptr))) {
197        case kPngError:
198            // There was an error. Stop processing data.
199            // FIXME: Do we need to discard png_ptr?
200            return false;
201        case kStopDecoding:
202            // We decoded all the lines we want.
203            return true;
204        case kSetJmpOkay:
205            // Everything is okay.
206            break;
207        default:
208            // No other values should be passed to longjmp.
209            SkASSERT(false);
210    }
211
212    // Arbitrary buffer size
213#ifdef TURBO_PNG_MULTY_LINE_OPT
214    // OH ISSUE: png optimize
215    constexpr size_t kBufferSize = 65536; // 65536, expand buffer to improve performance
216#else
217    constexpr size_t kBufferSize = 4096;
218#endif
219    char buffer[kBufferSize];
220
221    bool iend = false;
222    while (true) {
223        size_t length;
224        if (fDecodedIdat) {
225            // Parse chunk length and type.
226            if (this->stream()->read(buffer, 8) < 8) {
227                break;
228            }
229
230            png_byte* chunk = reinterpret_cast<png_byte*>(buffer);
231            png_process_data(fPng_ptr, fInfo_ptr, chunk, 8);
232            if (is_chunk(chunk, "IEND")) {
233                iend = true;
234            }
235
236            length = png_get_uint_32(chunk);
237        } else {
238            length = fIdatLength;
239            png_byte idat[] = {0, 0, 0, 0, 'I', 'D', 'A', 'T'};
240            png_save_uint_32(idat, length);
241            png_process_data(fPng_ptr, fInfo_ptr, idat, 8);
242            fDecodedIdat = true;
243        }
244
245        // Process the full chunk + CRC.
246        if (!process_data(fPng_ptr, fInfo_ptr, this->stream(), buffer, kBufferSize, length + 4)
247                || iend) {
248            break;
249        }
250    }
251
252    return true;
253}
254
255static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
256
257static inline bool needs_premul(SkAlphaType dstAT, SkEncodedInfo::Alpha encodedAlpha) {
258    return kPremul_SkAlphaType == dstAT && SkEncodedInfo::kUnpremul_Alpha == encodedAlpha;
259}
260
261// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
262bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
263
264    int numColors;
265    png_color* palette;
266    if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
267        return false;
268    }
269
270    // Contents depend on tableColorType and our choice of if/when to premultiply:
271    // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA }
272    SkPMColor colorTable[256];
273    SkColorType tableColorType = this->colorXform() ? kXformSrcColorType : dstInfo.colorType();
274
275    png_bytep alphas;
276    int numColorsWithAlpha = 0;
277    if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
278        bool premultiply = needs_premul(dstInfo.alphaType(), this->getEncodedInfo().alpha());
279
280        // Choose which function to use to create the color table. If the final destination's
281        // colortype is unpremultiplied, the color table will store unpremultiplied colors.
282        PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType);
283
284        for (int i = 0; i < numColorsWithAlpha; i++) {
285            // We don't have a function in SkOpts that combines a set of alphas with a set
286            // of RGBs.  We could write one, but it's hardly worth it, given that this
287            // is such a small fraction of the total decode time.
288            colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
289            palette++;
290        }
291    }
292
293    if (numColorsWithAlpha < numColors) {
294        // The optimized code depends on a 3-byte png_color struct with the colors
295        // in RGB order.  These checks make sure it is safe to use.
296        static_assert(3 == sizeof(png_color), "png_color struct has changed.  Opts are broken.");
297#ifdef SK_DEBUG
298        SkASSERT(&palette->red < &palette->green);
299        SkASSERT(&palette->green < &palette->blue);
300#endif
301
302        if (is_rgba(tableColorType)) {
303            SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, (const uint8_t*)palette,
304                    numColors - numColorsWithAlpha);
305        } else {
306            SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, (const uint8_t*)palette,
307                    numColors - numColorsWithAlpha);
308        }
309    }
310
311    if (this->colorXform() && !this->xformOnDecode()) {
312        this->applyColorXform(colorTable, colorTable, numColors);
313    }
314
315    // Pad the color table with the last color in the table (or black) in the case that
316    // invalid pixel indices exceed the number of colors in the table.
317    const int maxColors = 1 << fBitDepth;
318    if (numColors < maxColors) {
319        SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK;
320        sk_memset32(colorTable + numColors, lastColor, maxColors - numColors);
321    }
322
323    fColorTable.reset(new SkColorTable(colorTable, maxColors));
324    return true;
325}
326
327///////////////////////////////////////////////////////////////////////////////
328// Creation
329///////////////////////////////////////////////////////////////////////////////
330
331bool SkPngCodec::IsPng(const void* buf, size_t bytesRead) {
332    return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
333}
334
335#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
336
337static float png_fixed_point_to_float(png_fixed_point x) {
338    // We multiply by the same factor that libpng used to convert
339    // fixed point -> double.  Since we want floats, we choose to
340    // do the conversion ourselves rather than convert
341    // fixed point -> double -> float.
342    return ((float) x) * 0.00001f;
343}
344
345static float png_inverted_fixed_point_to_float(png_fixed_point x) {
346    // This is necessary because the gAMA chunk actually stores 1/gamma.
347    return 1.0f / png_fixed_point_to_float(x);
348}
349
350#endif // LIBPNG >= 1.6
351
352// If there is no color profile information, it will use sRGB.
353std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(png_structp png_ptr,
354                                                              png_infop info_ptr) {
355
356#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
357    // First check for an ICC profile
358    png_bytep profile;
359    png_uint_32 length;
360    // The below variables are unused, however, we need to pass them in anyway or
361    // png_get_iCCP() will return nothing.
362    // Could knowing the |name| of the profile ever be interesting?  Maybe for debugging?
363    png_charp name;
364    // The |compression| is uninteresting since:
365    //   (1) libpng has already decompressed the profile for us.
366    //   (2) "deflate" is the only mode of decompression that libpng supports.
367    int compression;
368    if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
369            &length)) {
370        auto data = SkData::MakeWithCopy(profile, length);
371        return SkEncodedInfo::ICCProfile::Make(std::move(data));
372    }
373
374    // Second, check for sRGB.
375    // Note that Blink does this first. This code checks ICC first, with the thinking that
376    // an image has both truly wants the potentially more specific ICC chunk, with sRGB as a
377    // backup in case the decoder does not support full color management.
378    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
379        // sRGB chunks also store a rendering intent: Absolute, Relative,
380        // Perceptual, and Saturation.
381        // FIXME (scroggo): Extract this information from the sRGB chunk once
382        //                  we are able to handle this information in
383        //                  skcms_ICCProfile
384        return nullptr;
385    }
386
387    // Default to SRGB gamut.
388    skcms_Matrix3x3 toXYZD50 = skcms_sRGB_profile()->toXYZD50;
389    // Next, check for chromaticities.
390    png_fixed_point chrm[8];
391    png_fixed_point gamma;
392    if (png_get_cHRM_fixed(png_ptr, info_ptr, &chrm[0], &chrm[1], &chrm[2], &chrm[3], &chrm[4],
393                           &chrm[5], &chrm[6], &chrm[7]))
394    {
395        float rx = png_fixed_point_to_float(chrm[2]);
396        float ry = png_fixed_point_to_float(chrm[3]);
397        float gx = png_fixed_point_to_float(chrm[4]);
398        float gy = png_fixed_point_to_float(chrm[5]);
399        float bx = png_fixed_point_to_float(chrm[6]);
400        float by = png_fixed_point_to_float(chrm[7]);
401        float wx = png_fixed_point_to_float(chrm[0]);
402        float wy = png_fixed_point_to_float(chrm[1]);
403
404        skcms_Matrix3x3 tmp;
405        if (skcms_PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, &tmp)) {
406            toXYZD50 = tmp;
407        } else {
408            // Note that Blink simply returns nullptr in this case. We'll fall
409            // back to srgb.
410        }
411    }
412
413    skcms_TransferFunction fn;
414    if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
415        fn.a = 1.0f;
416        fn.b = fn.c = fn.d = fn.e = fn.f = 0.0f;
417        fn.g = png_inverted_fixed_point_to_float(gamma);
418    } else {
419        // Default to sRGB gamma if the image has color space information,
420        // but does not specify gamma.
421        // Note that Blink would again return nullptr in this case.
422        fn = *skcms_sRGB_TransferFunction();
423    }
424
425    skcms_ICCProfile skcmsProfile;
426    skcms_Init(&skcmsProfile);
427    skcms_SetTransferFunction(&skcmsProfile, &fn);
428    skcms_SetXYZD50(&skcmsProfile, &toXYZD50);
429
430    return SkEncodedInfo::ICCProfile::Make(skcmsProfile);
431#else // LIBPNG >= 1.6
432    return nullptr;
433#endif // LIBPNG >= 1.6
434}
435
436void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
437    switch (fXformMode) {
438        case kSwizzleOnly_XformMode:
439            break;
440        case kColorOnly_XformMode:
441            // Intentional fall through.  A swizzler hasn't been created yet, but one will
442            // be created later if we are sampling.  We'll go ahead and allocate
443            // enough memory to swizzle if necessary.
444        case kSwizzleColor_XformMode: {
445            const int bitsPerPixel = this->getEncodedInfo().bitsPerPixel();
446
447            // If we have more than 8-bits (per component) of precision, we will keep that
448            // extra precision.  Otherwise, we will swizzle to RGBA_8888 before transforming.
449            const size_t bytesPerPixel = (bitsPerPixel > 32) ? bitsPerPixel / 8 : 4;
450            const size_t colorXformBytes = dstInfo.width() * bytesPerPixel;
451            fStorage.reset(colorXformBytes);
452            fColorXformSrcRow = fStorage.get();
453            break;
454        }
455    }
456}
457
458static skcms_PixelFormat png_select_xform_format(const SkEncodedInfo& info) {
459    // We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA.
460    if (16 == info.bitsPerComponent()) {
461        if (SkEncodedInfo::kRGBA_Color == info.color()) {
462            return skcms_PixelFormat_RGBA_16161616BE;
463        } else if (SkEncodedInfo::kRGB_Color == info.color()) {
464            return skcms_PixelFormat_RGB_161616BE;
465        }
466    } else if (SkEncodedInfo::kGray_Color == info.color()) {
467        return skcms_PixelFormat_G_8;
468    }
469
470    return skcms_PixelFormat_RGBA_8888;
471}
472
473void SkPngCodec::applyXformRow(void* dst, const void* src) {
474    switch (fXformMode) {
475        case kSwizzleOnly_XformMode:
476            fSwizzler->swizzle(dst, (const uint8_t*) src);
477            break;
478        case kColorOnly_XformMode:
479            this->applyColorXform(dst, src, fXformWidth);
480            break;
481        case kSwizzleColor_XformMode:
482            fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src);
483            this->applyColorXform(dst, fColorXformSrcRow, fXformWidth);
484            break;
485    }
486}
487
488static SkCodec::Result log_and_return_error(bool success) {
489    if (success) return SkCodec::kIncompleteInput;
490#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
491    SkAndroidFrameworkUtils::SafetyNetLog("117838472");
492#endif
493    return SkCodec::kErrorInInput;
494}
495
496class SkPngNormalDecoder : public SkPngCodec {
497public:
498    SkPngNormalDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
499            SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
500        : INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
501        , fRowsWrittenToOutput(0)
502        , fDst(nullptr)
503        , fRowBytes(0)
504        , fFirstRow(0)
505        , fLastRow(0)
506    {}
507
508    static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
509        GetDecoder(png_ptr)->allRowsCallback(row, rowNum);
510    }
511
512    static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
513        GetDecoder(png_ptr)->rowCallback(row, rowNum);
514    }
515
516private:
517    int                         fRowsWrittenToOutput;
518    void*                       fDst;
519    size_t                      fRowBytes;
520
521    // Variables for partial decode
522    int                         fFirstRow;  // FIXME: Move to baseclass?
523    int                         fLastRow;
524    int                         fRowsNeeded;
525
526    using INHERITED = SkPngCodec;
527
528    static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) {
529        return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr));
530    }
531
532    Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
533        const int height = this->dimensions().height();
534        png_set_progressive_read_fn(this->png_ptr(), this, nullptr, AllRowsCallback, nullptr);
535        fDst = dst;
536        fRowBytes = rowBytes;
537
538        fRowsWrittenToOutput = 0;
539        fFirstRow = 0;
540        fLastRow = height - 1;
541
542        const bool success = this->processData();
543        if (success && fRowsWrittenToOutput == height) {
544            return kSuccess;
545        }
546
547        if (rowsDecoded) {
548            *rowsDecoded = fRowsWrittenToOutput;
549        }
550
551        return log_and_return_error(success);
552    }
553
554    void allRowsCallback(png_bytep row, int rowNum) {
555        SkASSERT(rowNum == fRowsWrittenToOutput);
556        fRowsWrittenToOutput++;
557        this->applyXformRow(fDst, row);
558        fDst = SkTAddOffset<void>(fDst, fRowBytes);
559    }
560
561    void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
562        png_set_progressive_read_fn(this->png_ptr(), this, nullptr, RowCallback, nullptr);
563        fFirstRow = firstRow;
564        fLastRow = lastRow;
565        fDst = dst;
566        fRowBytes = rowBytes;
567        fRowsWrittenToOutput = 0;
568        fRowsNeeded = fLastRow - fFirstRow + 1;
569    }
570
571    Result decode(int* rowsDecoded) override {
572        if (this->swizzler()) {
573            const int sampleY = this->swizzler()->sampleY();
574            fRowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
575        }
576
577        const bool success = this->processData();
578        if (success && fRowsWrittenToOutput == fRowsNeeded) {
579            return kSuccess;
580        }
581
582        if (rowsDecoded) {
583            *rowsDecoded = fRowsWrittenToOutput;
584        }
585
586        return log_and_return_error(success);
587    }
588
589    void rowCallback(png_bytep row, int rowNum) {
590        if (rowNum < fFirstRow) {
591            // Ignore this row.
592            return;
593        }
594
595        SkASSERT(rowNum <= fLastRow);
596        SkASSERT(fRowsWrittenToOutput < fRowsNeeded);
597
598        // If there is no swizzler, all rows are needed.
599        if (!this->swizzler() || this->swizzler()->rowNeeded(rowNum - fFirstRow)) {
600            this->applyXformRow(fDst, row);
601            fDst = SkTAddOffset<void>(fDst, fRowBytes);
602            fRowsWrittenToOutput++;
603        }
604
605        if (fRowsWrittenToOutput == fRowsNeeded) {
606            // Fake error to stop decoding scanlines.
607            longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
608        }
609    }
610};
611
612class SkPngInterlacedDecoder : public SkPngCodec {
613public:
614    SkPngInterlacedDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
615            SkPngChunkReader* reader, png_structp png_ptr,
616            png_infop info_ptr, int bitDepth, int numberPasses)
617        : INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
618        , fNumberPasses(numberPasses)
619        , fFirstRow(0)
620        , fLastRow(0)
621        , fLinesDecoded(0)
622        , fInterlacedComplete(false)
623        , fPng_rowbytes(0)
624    {}
625
626    static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int pass) {
627        auto decoder = static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr));
628        decoder->interlacedRowCallback(row, rowNum, pass);
629    }
630
631private:
632    const int               fNumberPasses;
633    int                     fFirstRow;
634    int                     fLastRow;
635    void*                   fDst;
636    size_t                  fRowBytes;
637    int                     fLinesDecoded;
638    bool                    fInterlacedComplete;
639    size_t                  fPng_rowbytes;
640    SkAutoTMalloc<png_byte> fInterlaceBuffer;
641
642    using INHERITED = SkPngCodec;
643
644    // FIXME: Currently sharing interlaced callback for all rows and subset. It's not
645    // as expensive as the subset version of non-interlaced, but it still does extra
646    // work.
647    void interlacedRowCallback(png_bytep row, int rowNum, int pass) {
648        if (rowNum < fFirstRow || rowNum > fLastRow || fInterlacedComplete) {
649            // Ignore this row
650            return;
651        }
652
653        png_bytep oldRow = fInterlaceBuffer.get() + (rowNum - fFirstRow) * fPng_rowbytes;
654        png_progressive_combine_row(this->png_ptr(), oldRow, row);
655
656        if (0 == pass) {
657            // The first pass initializes all rows.
658            SkASSERT(row);
659            SkASSERT(fLinesDecoded == rowNum - fFirstRow);
660            fLinesDecoded++;
661        } else {
662            SkASSERT(fLinesDecoded == fLastRow - fFirstRow + 1);
663            if (fNumberPasses - 1 == pass && rowNum == fLastRow) {
664                // Last pass, and we have read all of the rows we care about.
665                fInterlacedComplete = true;
666                if (fLastRow != this->dimensions().height() - 1 ||
667                        (this->swizzler() && this->swizzler()->sampleY() != 1)) {
668                    // Fake error to stop decoding scanlines. Only stop if we're not decoding the
669                    // whole image, in which case processing the rest of the image might be
670                    // expensive. When decoding the whole image, read through the IEND chunk to
671                    // preserve Android behavior of leaving the input stream in the right place.
672                    longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
673                }
674            }
675        }
676    }
677
678    Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
679        const int height = this->dimensions().height();
680        this->setUpInterlaceBuffer(height);
681        png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback,
682                                    nullptr);
683
684        fFirstRow = 0;
685        fLastRow = height - 1;
686        fLinesDecoded = 0;
687
688        const bool success = this->processData();
689        png_bytep srcRow = fInterlaceBuffer.get();
690        // FIXME: When resuming, this may rewrite rows that did not change.
691        for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) {
692            this->applyXformRow(dst, srcRow);
693            dst = SkTAddOffset<void>(dst, rowBytes);
694            srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes);
695        }
696        if (success && fInterlacedComplete) {
697            return kSuccess;
698        }
699
700        if (rowsDecoded) {
701            *rowsDecoded = fLinesDecoded;
702        }
703
704        return log_and_return_error(success);
705    }
706
707    void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
708        // FIXME: We could skip rows in the interlace buffer that we won't put in the output.
709        this->setUpInterlaceBuffer(lastRow - firstRow + 1);
710        png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback, nullptr);
711        fFirstRow = firstRow;
712        fLastRow = lastRow;
713        fDst = dst;
714        fRowBytes = rowBytes;
715        fLinesDecoded = 0;
716    }
717
718    Result decode(int* rowsDecoded) override {
719        const bool success = this->processData();
720
721        // Now apply Xforms on all the rows that were decoded.
722        if (!fLinesDecoded) {
723            if (rowsDecoded) {
724                *rowsDecoded = 0;
725            }
726            return log_and_return_error(success);
727        }
728
729        const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1;
730        const int rowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
731
732        // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it
733        // may be too tricky/expensive to handle that correctly.
734
735        // Offset srcRow by get_start_coord rows. We do not need to account for fFirstRow,
736        // since the first row in fInterlaceBuffer corresponds to fFirstRow.
737        int srcRow = get_start_coord(sampleY);
738        void* dst = fDst;
739        int rowsWrittenToOutput = 0;
740        while (rowsWrittenToOutput < rowsNeeded && srcRow < fLinesDecoded) {
741            png_bytep src = SkTAddOffset<png_byte>(fInterlaceBuffer.get(), fPng_rowbytes * srcRow);
742            this->applyXformRow(dst, src);
743            dst = SkTAddOffset<void>(dst, fRowBytes);
744
745            rowsWrittenToOutput++;
746            srcRow += sampleY;
747        }
748
749        if (success && fInterlacedComplete) {
750            return kSuccess;
751        }
752
753        if (rowsDecoded) {
754            *rowsDecoded = rowsWrittenToOutput;
755        }
756        return log_and_return_error(success);
757    }
758
759    void setUpInterlaceBuffer(int height) {
760        fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr());
761        fInterlaceBuffer.reset(fPng_rowbytes * height);
762        fInterlacedComplete = false;
763    }
764};
765
766// Reads the header and initializes the output fields, if not NULL.
767//
768// @param stream Input data. Will be read to get enough information to properly
769//      setup the codec.
770// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
771//      If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
772//      expected to continue to own it for the lifetime of the png_ptr.
773// @param outCodec Optional output variable.  If non-NULL, will be set to a new
774//      SkPngCodec on success.
775// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
776//      png_structp on success.
777// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
778//      png_infop on success;
779// @return if kSuccess, the caller is responsible for calling
780//      png_destroy_read_struct(png_ptrp, info_ptrp).
781//      Otherwise, the passed in fields (except stream) are unchanged.
782static SkCodec::Result read_header(SkStream* stream, SkPngChunkReader* chunkReader,
783                                   SkCodec** outCodec,
784                                   png_structp* png_ptrp, png_infop* info_ptrp) {
785    // The image is known to be a PNG. Decode enough to know the SkImageInfo.
786    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
787                                                 sk_error_fn, sk_warning_fn);
788    if (!png_ptr) {
789        return SkCodec::kInternalError;
790    }
791
792#ifdef PNG_SET_OPTION_SUPPORTED
793    // This setting ensures that we display images with incorrect CMF bytes.
794    // See crbug.com/807324.
795    png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
796#endif
797
798    AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec);
799
800    png_infop info_ptr = png_create_info_struct(png_ptr);
801    if (info_ptr == nullptr) {
802        return SkCodec::kInternalError;
803    }
804
805    autoClean.setInfoPtr(info_ptr);
806
807    if (setjmp(PNG_JMPBUF(png_ptr))) {
808        return SkCodec::kInvalidInput;
809    }
810
811#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
812    // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
813    // This needs to be installed before we read the png header.  Android may store ninepatch
814    // chunks in the header.
815    if (chunkReader) {
816        png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
817        png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
818    }
819#endif
820
821    const bool decodedBounds = autoClean.decodeBounds();
822
823    if (!decodedBounds) {
824        return SkCodec::kIncompleteInput;
825    }
826
827    // On success, decodeBounds releases ownership of png_ptr and info_ptr.
828    if (png_ptrp) {
829        *png_ptrp = png_ptr;
830    }
831    if (info_ptrp) {
832        *info_ptrp = info_ptr;
833    }
834
835    // decodeBounds takes care of setting outCodec
836    if (outCodec) {
837        SkASSERT(*outCodec);
838    }
839    return SkCodec::kSuccess;
840}
841
842void AutoCleanPng::infoCallback(size_t idatLength) {
843    png_uint_32 origWidth, origHeight;
844    int bitDepth, encodedColorType;
845    png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth,
846                 &encodedColorType, nullptr, nullptr, nullptr);
847
848    // TODO: Should we support 16-bits of precision for gray images?
849    if (bitDepth == 16 && (PNG_COLOR_TYPE_GRAY == encodedColorType ||
850                           PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType)) {
851        bitDepth = 8;
852        png_set_strip_16(fPng_ptr);
853    }
854
855    // Now determine the default colorType and alphaType and set the required transforms.
856    // Often, we depend on SkSwizzler to perform any transforms that we need.  However, we
857    // still depend on libpng for many of the rare and PNG-specific cases.
858    SkEncodedInfo::Color color;
859    SkEncodedInfo::Alpha alpha;
860    switch (encodedColorType) {
861        case PNG_COLOR_TYPE_PALETTE:
862            // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
863            // byte into separate bytes (useful for paletted and grayscale images).
864            if (bitDepth < 8) {
865                // TODO: Should we use SkSwizzler here?
866                bitDepth = 8;
867                png_set_packing(fPng_ptr);
868            }
869
870            color = SkEncodedInfo::kPalette_Color;
871            // Set the alpha depending on if a transparency chunk exists.
872            alpha = png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS) ?
873                    SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha;
874            break;
875        case PNG_COLOR_TYPE_RGB:
876            if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
877                // Convert to RGBA if transparency chunk exists.
878                png_set_tRNS_to_alpha(fPng_ptr);
879                color = SkEncodedInfo::kRGBA_Color;
880                alpha = SkEncodedInfo::kBinary_Alpha;
881            } else {
882                color = SkEncodedInfo::kRGB_Color;
883                alpha = SkEncodedInfo::kOpaque_Alpha;
884            }
885            break;
886        case PNG_COLOR_TYPE_GRAY:
887            // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
888            if (bitDepth < 8) {
889                // TODO: Should we use SkSwizzler here?
890                bitDepth = 8;
891                png_set_expand_gray_1_2_4_to_8(fPng_ptr);
892            }
893
894            if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
895                png_set_tRNS_to_alpha(fPng_ptr);
896                color = SkEncodedInfo::kGrayAlpha_Color;
897                alpha = SkEncodedInfo::kBinary_Alpha;
898            } else {
899                color = SkEncodedInfo::kGray_Color;
900                alpha = SkEncodedInfo::kOpaque_Alpha;
901            }
902            break;
903        case PNG_COLOR_TYPE_GRAY_ALPHA:
904            color = SkEncodedInfo::kGrayAlpha_Color;
905            alpha = SkEncodedInfo::kUnpremul_Alpha;
906            break;
907        case PNG_COLOR_TYPE_RGBA:
908            color = SkEncodedInfo::kRGBA_Color;
909            alpha = SkEncodedInfo::kUnpremul_Alpha;
910            break;
911        default:
912            // All the color types have been covered above.
913            SkASSERT(false);
914            color = SkEncodedInfo::kRGBA_Color;
915            alpha = SkEncodedInfo::kUnpremul_Alpha;
916    }
917
918    const int numberPasses = png_set_interlace_handling(fPng_ptr);
919
920    if (fOutCodec) {
921        SkASSERT(nullptr == *fOutCodec);
922        auto profile = read_color_profile(fPng_ptr, fInfo_ptr);
923        if (profile) {
924            switch (profile->profile()->data_color_space) {
925                case skcms_Signature_CMYK:
926                    profile = nullptr;
927                    break;
928                case skcms_Signature_Gray:
929                    if (SkEncodedInfo::kGray_Color != color &&
930                        SkEncodedInfo::kGrayAlpha_Color != color)
931                    {
932                        profile = nullptr;
933                    }
934                    break;
935                default:
936                    break;
937            }
938        }
939
940        switch (encodedColorType) {
941            case PNG_COLOR_TYPE_GRAY_ALPHA:{
942                png_color_8p sigBits;
943                if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
944                    if (8 == sigBits->alpha && kGraySigBit_GrayAlphaIsJustAlpha == sigBits->gray) {
945                        color = SkEncodedInfo::kXAlpha_Color;
946                    }
947                }
948                break;
949            }
950            case PNG_COLOR_TYPE_RGB:{
951                png_color_8p sigBits;
952                if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
953                    if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
954                        // Recommend a decode to 565 if the sBIT indicates 565.
955                        color = SkEncodedInfo::k565_Color;
956                    }
957                }
958                break;
959            }
960        }
961
962#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
963        if (encodedColorType != PNG_COLOR_TYPE_GRAY_ALPHA
964            && SkEncodedInfo::kOpaque_Alpha == alpha) {
965            png_color_8p sigBits;
966            if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
967                if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
968                    SkAndroidFrameworkUtils::SafetyNetLog("190188264");
969                }
970            }
971        }
972#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK
973
974        SkEncodedInfo encodedInfo = SkEncodedInfo::Make(origWidth, origHeight, color, alpha,
975                                                        bitDepth, std::move(profile));
976        if (1 == numberPasses) {
977            *fOutCodec = new SkPngNormalDecoder(std::move(encodedInfo),
978                   std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth);
979        } else {
980            *fOutCodec = new SkPngInterlacedDecoder(std::move(encodedInfo),
981                    std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth,
982                    numberPasses);
983        }
984        static_cast<SkPngCodec*>(*fOutCodec)->setIdatLength(idatLength);
985    }
986
987    // Release the pointers, which are now owned by the codec or the caller is expected to
988    // take ownership.
989    this->releasePngPtrs();
990}
991
992SkPngCodec::SkPngCodec(SkEncodedInfo&& encodedInfo, std::unique_ptr<SkStream> stream,
993                       SkPngChunkReader* chunkReader, void* png_ptr, void* info_ptr, int bitDepth)
994    : INHERITED(std::move(encodedInfo), png_select_xform_format(encodedInfo), std::move(stream))
995    , fPngChunkReader(SkSafeRef(chunkReader))
996    , fPng_ptr(png_ptr)
997    , fInfo_ptr(info_ptr)
998    , fColorXformSrcRow(nullptr)
999    , fBitDepth(bitDepth)
1000    , fIdatLength(0)
1001    , fDecodedIdat(false)
1002{}
1003
1004SkPngCodec::~SkPngCodec() {
1005    this->destroyReadStruct();
1006}
1007
1008void SkPngCodec::destroyReadStruct() {
1009    if (fPng_ptr) {
1010        // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
1011        SkASSERT(fInfo_ptr);
1012        png_destroy_read_struct((png_struct**)&fPng_ptr, (png_info**)&fInfo_ptr, nullptr);
1013        fPng_ptr = nullptr;
1014        fInfo_ptr = nullptr;
1015    }
1016}
1017
1018///////////////////////////////////////////////////////////////////////////////
1019// Getting the pixels
1020///////////////////////////////////////////////////////////////////////////////
1021
1022SkCodec::Result SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options) {
1023    if (setjmp(PNG_JMPBUF((png_struct*)fPng_ptr))) {
1024        SkCodecPrintf("Failed on png_read_update_info.\n");
1025        return kInvalidInput;
1026    }
1027    png_read_update_info(fPng_ptr, fInfo_ptr);
1028
1029    // Reset fSwizzler and this->colorXform().  We can't do this in onRewind() because the
1030    // interlaced scanline decoder may need to rewind.
1031    fSwizzler.reset(nullptr);
1032
1033    // If skcms directly supports the encoded PNG format, we should skip format
1034    // conversion in the swizzler (or skip swizzling altogether).
1035    bool skipFormatConversion = false;
1036    switch (this->getEncodedInfo().color()) {
1037        case SkEncodedInfo::kRGB_Color:
1038            if (this->getEncodedInfo().bitsPerComponent() != 16) {
1039                break;
1040            }
1041            [[fallthrough]];
1042        case SkEncodedInfo::kRGBA_Color:
1043        case SkEncodedInfo::kGray_Color:
1044            skipFormatConversion = this->colorXform();
1045            break;
1046        default:
1047            break;
1048    }
1049    if (skipFormatConversion && !options.fSubset) {
1050        fXformMode = kColorOnly_XformMode;
1051        return kSuccess;
1052    }
1053
1054    if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
1055        if (!this->createColorTable(dstInfo)) {
1056            return kInvalidInput;
1057        }
1058    }
1059
1060    this->initializeSwizzler(dstInfo, options, skipFormatConversion);
1061    return kSuccess;
1062}
1063
1064void SkPngCodec::initializeXformParams() {
1065    switch (fXformMode) {
1066        case kColorOnly_XformMode:
1067            fXformWidth = this->dstInfo().width();
1068            break;
1069        case kSwizzleColor_XformMode:
1070            fXformWidth = this->swizzler()->swizzleWidth();
1071            break;
1072        default:
1073            break;
1074    }
1075}
1076
1077void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
1078                                    bool skipFormatConversion) {
1079    SkImageInfo swizzlerInfo = dstInfo;
1080    Options swizzlerOptions = options;
1081    fXformMode = kSwizzleOnly_XformMode;
1082    if (this->colorXform() && this->xformOnDecode()) {
1083        if (SkEncodedInfo::kGray_Color == this->getEncodedInfo().color()) {
1084            swizzlerInfo = swizzlerInfo.makeColorType(kGray_8_SkColorType);
1085        } else {
1086            swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType);
1087        }
1088        if (kPremul_SkAlphaType == dstInfo.alphaType()) {
1089            swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
1090        }
1091
1092        fXformMode = kSwizzleColor_XformMode;
1093
1094        // Here, we swizzle into temporary memory, which is not zero initialized.
1095        // FIXME (msarett):
1096        // Is this a problem?
1097        swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized;
1098    }
1099
1100    if (skipFormatConversion) {
1101        // We cannot skip format conversion when there is a color table.
1102        SkASSERT(!fColorTable);
1103        int srcBPP = 0;
1104        switch (this->getEncodedInfo().color()) {
1105            case SkEncodedInfo::kRGB_Color:
1106                SkASSERT(this->getEncodedInfo().bitsPerComponent() == 16);
1107                srcBPP = 6;
1108                break;
1109            case SkEncodedInfo::kRGBA_Color:
1110                srcBPP = this->getEncodedInfo().bitsPerComponent() / 2;
1111                break;
1112            case SkEncodedInfo::kGray_Color:
1113                srcBPP = 1;
1114                break;
1115            default:
1116                SkASSERT(false);
1117                break;
1118        }
1119        fSwizzler = SkSwizzler::MakeSimple(srcBPP, swizzlerInfo, swizzlerOptions);
1120    } else {
1121        const SkPMColor* colors = get_color_ptr(fColorTable.get());
1122        fSwizzler = SkSwizzler::Make(this->getEncodedInfo(), colors, swizzlerInfo,
1123                                     swizzlerOptions);
1124    }
1125    SkASSERT(fSwizzler);
1126}
1127
1128SkSampler* SkPngCodec::getSampler(bool createIfNecessary) {
1129    if (fSwizzler || !createIfNecessary) {
1130        return fSwizzler.get();
1131    }
1132
1133    this->initializeSwizzler(this->dstInfo(), this->options(), true);
1134    return fSwizzler.get();
1135}
1136
1137bool SkPngCodec::onRewind() {
1138    // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
1139    // succeeds, they will be repopulated, and if it fails, they will
1140    // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
1141    // come through this function which will rewind and again attempt
1142    // to reinitialize them.
1143    this->destroyReadStruct();
1144
1145    png_structp png_ptr;
1146    png_infop info_ptr;
1147    if (kSuccess != read_header(this->stream(), fPngChunkReader.get(), nullptr,
1148                                &png_ptr, &info_ptr)) {
1149        return false;
1150    }
1151
1152    fPng_ptr = png_ptr;
1153    fInfo_ptr = info_ptr;
1154    fDecodedIdat = false;
1155    return true;
1156}
1157
1158SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
1159                                        size_t rowBytes, const Options& options,
1160                                        int* rowsDecoded) {
1161    Result result = this->initializeXforms(dstInfo, options);
1162    if (kSuccess != result) {
1163        return result;
1164    }
1165
1166    if (options.fSubset) {
1167        return kUnimplemented;
1168    }
1169
1170    this->allocateStorage(dstInfo);
1171    this->initializeXformParams();
1172    return this->decodeAllRows(dst, rowBytes, rowsDecoded);
1173}
1174
1175SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
1176        void* dst, size_t rowBytes, const SkCodec::Options& options) {
1177    Result result = this->initializeXforms(dstInfo, options);
1178    if (kSuccess != result) {
1179        return result;
1180    }
1181
1182    this->allocateStorage(dstInfo);
1183
1184    int firstRow, lastRow;
1185    if (options.fSubset) {
1186        firstRow = options.fSubset->top();
1187        lastRow = options.fSubset->bottom() - 1;
1188    } else {
1189        firstRow = 0;
1190        lastRow = dstInfo.height() - 1;
1191    }
1192    this->setRange(firstRow, lastRow, dst, rowBytes);
1193    return kSuccess;
1194}
1195
1196SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) {
1197    // FIXME: Only necessary on the first call.
1198    this->initializeXformParams();
1199
1200    return this->decode(rowsDecoded);
1201}
1202
1203std::unique_ptr<SkCodec> SkPngCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
1204                                                    Result* result, SkPngChunkReader* chunkReader) {
1205    SkCodec* outCodec = nullptr;
1206    *result = read_header(stream.get(), chunkReader, &outCodec, nullptr, nullptr);
1207    if (kSuccess == *result) {
1208        // Codec has taken ownership of the stream.
1209        SkASSERT(outCodec);
1210        stream.release();
1211    }
1212    return std::unique_ptr<SkCodec>(outCodec);
1213}
1214