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