blob: df77b3aac09153badd1e69109924f8723aacd6b0 [file] [log] [blame]
scroggof24f2242015-03-03 08:59:20 -08001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#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#include "src/core/SkUtils.h"
scroggof24f2242015-03-03 08:59:20 -080024
mtklein63213812016-08-24 09:55:56 -070025#include "png.h"
Leon Scroggins III83239652017-04-21 13:47:12 -040026#include <algorithm>
mtklein63213812016-08-24 09:55:56 -070027
Leon Scroggins III44764002018-11-13 10:26:34 -050028#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029 #include "include/android/SkAndroidFrameworkUtils.h"
Leon Scroggins III44764002018-11-13 10:26:34 -050030#endif
31
mtkleindc90b532016-07-28 14:45:28 -070032// This warning triggers false postives way too often in here.
33#if defined(__GNUC__) && !defined(__clang__)
34 #pragma GCC diagnostic ignored "-Wclobbered"
35#endif
36
scroggo8e6c7ad2016-09-16 08:20:38 -070037// FIXME (scroggo): We can use png_jumpbuf directly once Google3 is on 1.6
38#define PNG_JMPBUF(x) png_jmpbuf((png_structp) x)
39
scroggof24f2242015-03-03 08:59:20 -080040///////////////////////////////////////////////////////////////////////////////
scroggof24f2242015-03-03 08:59:20 -080041// Callback functions
42///////////////////////////////////////////////////////////////////////////////
43
scroggo8e6c7ad2016-09-16 08:20:38 -070044// When setjmp is first called, it returns 0, meaning longjmp was not called.
45constexpr int kSetJmpOkay = 0;
46// An error internal to libpng.
47constexpr int kPngError = 1;
48// Passed to longjmp when we have decoded as many lines as we need.
49constexpr int kStopDecoding = 2;
50
scroggof24f2242015-03-03 08:59:20 -080051static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
scroggo230d4ac2015-03-26 07:15:55 -070052 SkCodecPrintf("------ png error %s\n", msg);
scroggo8e6c7ad2016-09-16 08:20:38 -070053 longjmp(PNG_JMPBUF(png_ptr), kPngError);
scroggof24f2242015-03-03 08:59:20 -080054}
55
scroggo0eed6df2015-03-26 10:07:56 -070056void sk_warning_fn(png_structp, png_const_charp msg) {
57 SkCodecPrintf("----- png warning %s\n", msg);
58}
59
scroggocf98fa92015-11-23 08:14:40 -080060#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
61static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
62 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
63 // readChunk() returning true means continue decoding
64 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1;
65}
66#endif
67
scroggof24f2242015-03-03 08:59:20 -080068///////////////////////////////////////////////////////////////////////////////
69// Helpers
70///////////////////////////////////////////////////////////////////////////////
71
72class AutoCleanPng : public SkNoncopyable {
73public:
scroggo8e6c7ad2016-09-16 08:20:38 -070074 /*
75 * This class does not take ownership of stream or reader, but if codecPtr
76 * is non-NULL, and decodeBounds succeeds, it will have created a new
77 * SkCodec (pointed to by *codecPtr) which will own/ref them, as well as
78 * the png_ptr and info_ptr.
79 */
80 AutoCleanPng(png_structp png_ptr, SkStream* stream, SkPngChunkReader* reader,
81 SkCodec** codecPtr)
scroggof24f2242015-03-03 08:59:20 -080082 : fPng_ptr(png_ptr)
scroggo8e6c7ad2016-09-16 08:20:38 -070083 , fInfo_ptr(nullptr)
scroggo8e6c7ad2016-09-16 08:20:38 -070084 , fStream(stream)
85 , fChunkReader(reader)
86 , fOutCodec(codecPtr)
87 {}
scroggof24f2242015-03-03 08:59:20 -080088
89 ~AutoCleanPng() {
halcanary96fcdcc2015-08-27 07:41:13 -070090 // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
scroggof24f2242015-03-03 08:59:20 -080091 if (fPng_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -070092 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
msarett13a91232016-02-01 08:03:29 -080093 png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
scroggof24f2242015-03-03 08:59:20 -080094 }
95 }
96
97 void setInfoPtr(png_infop info_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -070098 SkASSERT(nullptr == fInfo_ptr);
scroggof24f2242015-03-03 08:59:20 -080099 fInfo_ptr = info_ptr;
100 }
101
scroggo8e6c7ad2016-09-16 08:20:38 -0700102 /**
103 * Reads enough of the input stream to decode the bounds.
104 * @return false if the stream is not a valid PNG (or too short).
105 * true if it read enough of the stream to determine the bounds.
106 * In the latter case, the stream may have been read beyond the
107 * point to determine the bounds, and the png_ptr will have saved
108 * any extra data. Further, if the codecPtr supplied to the
109 * constructor was not NULL, it will now point to a new SkCodec,
110 * which owns (or refs, in the case of the SkPngChunkReader) the
111 * inputs. If codecPtr was NULL, the png_ptr and info_ptr are
112 * unowned, and it is up to the caller to destroy them.
113 */
114 bool decodeBounds();
115
116private:
117 png_structp fPng_ptr;
118 png_infop fInfo_ptr;
scroggo8e6c7ad2016-09-16 08:20:38 -0700119 SkStream* fStream;
120 SkPngChunkReader* fChunkReader;
121 SkCodec** fOutCodec;
122
Leon Scroggins III83239652017-04-21 13:47:12 -0400123 void infoCallback(size_t idatLength);
scroggo8e6c7ad2016-09-16 08:20:38 -0700124
scroggo8e6c7ad2016-09-16 08:20:38 -0700125 void releasePngPtrs() {
halcanary96fcdcc2015-08-27 07:41:13 -0700126 fPng_ptr = nullptr;
127 fInfo_ptr = nullptr;
scroggof24f2242015-03-03 08:59:20 -0800128 }
scroggof24f2242015-03-03 08:59:20 -0800129};
130#define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
131
Leon Scroggins III83239652017-04-21 13:47:12 -0400132static inline bool is_chunk(const png_byte* chunk, const char* tag) {
133 return memcmp(chunk + 4, tag, 4) == 0;
134}
135
136static inline bool process_data(png_structp png_ptr, png_infop info_ptr,
137 SkStream* stream, void* buffer, size_t bufferSize, size_t length) {
138 while (length > 0) {
139 const size_t bytesToProcess = std::min(bufferSize, length);
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400140 const size_t bytesRead = stream->read(buffer, bytesToProcess);
141 png_process_data(png_ptr, info_ptr, (png_bytep) buffer, bytesRead);
142 if (bytesRead < bytesToProcess) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400143 return false;
144 }
Leon Scroggins III83239652017-04-21 13:47:12 -0400145 length -= bytesToProcess;
146 }
147 return true;
148}
149
scroggo8e6c7ad2016-09-16 08:20:38 -0700150bool AutoCleanPng::decodeBounds() {
151 if (setjmp(PNG_JMPBUF(fPng_ptr))) {
152 return false;
153 }
154
Leon Scroggins III83239652017-04-21 13:47:12 -0400155 png_set_progressive_read_fn(fPng_ptr, nullptr, nullptr, nullptr, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700156
157 // Arbitrary buffer size, though note that it matches (below)
158 // SkPngCodec::processData(). FIXME: Can we better suit this to the size of
159 // the PNG header?
160 constexpr size_t kBufferSize = 4096;
161 char buffer[kBufferSize];
162
Leon Scroggins III83239652017-04-21 13:47:12 -0400163 {
164 // Parse the signature.
165 if (fStream->read(buffer, 8) < 8) {
166 return false;
167 }
168
169 png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, 8);
170 }
171
scroggo8e6c7ad2016-09-16 08:20:38 -0700172 while (true) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400173 // Parse chunk length and type.
174 if (fStream->read(buffer, 8) < 8) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700175 // We have read to the end of the input without decoding bounds.
176 break;
177 }
178
Leon Scroggins III83239652017-04-21 13:47:12 -0400179 png_byte* chunk = reinterpret_cast<png_byte*>(buffer);
180 const size_t length = png_get_uint_32(chunk);
181
182 if (is_chunk(chunk, "IDAT")) {
183 this->infoCallback(length);
184 return true;
185 }
186
187 png_process_data(fPng_ptr, fInfo_ptr, chunk, 8);
188 // Process the full chunk + CRC.
189 if (!process_data(fPng_ptr, fInfo_ptr, fStream, buffer, kBufferSize, length + 4)) {
190 return false;
scroggo8e6c7ad2016-09-16 08:20:38 -0700191 }
192 }
193
Leon Scroggins III83239652017-04-21 13:47:12 -0400194 return false;
scroggo8e6c7ad2016-09-16 08:20:38 -0700195}
196
nagarajan.ndd7ffa52017-09-29 08:23:32 +0530197bool SkPngCodec::processData() {
scroggo8e6c7ad2016-09-16 08:20:38 -0700198 switch (setjmp(PNG_JMPBUF(fPng_ptr))) {
199 case kPngError:
200 // There was an error. Stop processing data.
201 // FIXME: Do we need to discard png_ptr?
Brian Salomon23356442018-11-30 15:33:19 -0500202 return false;
scroggo8e6c7ad2016-09-16 08:20:38 -0700203 case kStopDecoding:
204 // We decoded all the lines we want.
nagarajan.ndd7ffa52017-09-29 08:23:32 +0530205 return true;
scroggo8e6c7ad2016-09-16 08:20:38 -0700206 case kSetJmpOkay:
207 // Everything is okay.
208 break;
209 default:
210 // No other values should be passed to longjmp.
211 SkASSERT(false);
212 }
213
214 // Arbitrary buffer size
215 constexpr size_t kBufferSize = 4096;
216 char buffer[kBufferSize];
217
Leon Scroggins III83239652017-04-21 13:47:12 -0400218 bool iend = false;
scroggo8e6c7ad2016-09-16 08:20:38 -0700219 while (true) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400220 size_t length;
221 if (fDecodedIdat) {
222 // Parse chunk length and type.
223 if (this->stream()->read(buffer, 8) < 8) {
224 break;
225 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700226
Leon Scroggins III83239652017-04-21 13:47:12 -0400227 png_byte* chunk = reinterpret_cast<png_byte*>(buffer);
228 png_process_data(fPng_ptr, fInfo_ptr, chunk, 8);
229 if (is_chunk(chunk, "IEND")) {
230 iend = true;
231 }
232
233 length = png_get_uint_32(chunk);
234 } else {
235 length = fIdatLength;
236 png_byte idat[] = {0, 0, 0, 0, 'I', 'D', 'A', 'T'};
237 png_save_uint_32(idat, length);
238 png_process_data(fPng_ptr, fInfo_ptr, idat, 8);
239 fDecodedIdat = true;
240 }
241
242 // Process the full chunk + CRC.
243 if (!process_data(fPng_ptr, fInfo_ptr, this->stream(), buffer, kBufferSize, length + 4)
244 || iend) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700245 break;
246 }
247 }
nagarajan.ndd7ffa52017-09-29 08:23:32 +0530248
249 return true;
scroggo8e6c7ad2016-09-16 08:20:38 -0700250}
251
Leon Scroggins III862c1962017-10-02 16:28:49 -0400252static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
Matt Sarett562e6812016-11-08 16:13:43 -0500253
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400254static inline bool needs_premul(SkAlphaType dstAT, SkEncodedInfo::Alpha encodedAlpha) {
255 return kPremul_SkAlphaType == dstAT && SkEncodedInfo::kUnpremul_Alpha == encodedAlpha;
256}
257
msarettd1ec89b2016-08-03 12:59:27 -0700258// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
Leon Scroggins571b30f2017-07-11 17:35:31 +0000259bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
scroggof24f2242015-03-03 08:59:20 -0800260
msarett13a91232016-02-01 08:03:29 -0800261 int numColors;
262 png_color* palette;
263 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
scroggo05245902015-03-25 11:11:52 -0700264 return false;
scroggof24f2242015-03-03 08:59:20 -0800265 }
266
msarettdcd5e652016-08-22 08:48:40 -0700267 // Contents depend on tableColorType and our choice of if/when to premultiply:
268 // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA }
269 SkPMColor colorTable[256];
Matt Sarett562e6812016-11-08 16:13:43 -0500270 SkColorType tableColorType = this->colorXform() ? kXformSrcColorType : dstInfo.colorType();
scroggof24f2242015-03-03 08:59:20 -0800271
msarett13a91232016-02-01 08:03:29 -0800272 png_bytep alphas;
273 int numColorsWithAlpha = 0;
274 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400275 bool premultiply = needs_premul(dstInfo.alphaType(), this->getEncodedInfo().alpha());
msarettdcd5e652016-08-22 08:48:40 -0700276
msarett13a91232016-02-01 08:03:29 -0800277 // Choose which function to use to create the color table. If the final destination's
278 // colortype is unpremultiplied, the color table will store unpremultiplied colors.
msarettdcd5e652016-08-22 08:48:40 -0700279 PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType);
msarett13a91232016-02-01 08:03:29 -0800280
281 for (int i = 0; i < numColorsWithAlpha; i++) {
282 // We don't have a function in SkOpts that combines a set of alphas with a set
283 // of RGBs. We could write one, but it's hardly worth it, given that this
284 // is such a small fraction of the total decode time.
msarettdcd5e652016-08-22 08:48:40 -0700285 colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
msarett13a91232016-02-01 08:03:29 -0800286 palette++;
287 }
scroggof24f2242015-03-03 08:59:20 -0800288 }
289
msarett13a91232016-02-01 08:03:29 -0800290 if (numColorsWithAlpha < numColors) {
291 // The optimized code depends on a 3-byte png_color struct with the colors
292 // in RGB order. These checks make sure it is safe to use.
293 static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts are broken.");
294#ifdef SK_DEBUG
295 SkASSERT(&palette->red < &palette->green);
296 SkASSERT(&palette->green < &palette->blue);
297#endif
298
msarettdcd5e652016-08-22 08:48:40 -0700299 if (is_rgba(tableColorType)) {
Mike Klein6e78ae52018-09-19 13:37:16 -0400300 SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, (const uint8_t*)palette,
msarett34e0ec42016-04-22 16:27:24 -0700301 numColors - numColorsWithAlpha);
302 } else {
Mike Klein6e78ae52018-09-19 13:37:16 -0400303 SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, (const uint8_t*)palette,
msarett34e0ec42016-04-22 16:27:24 -0700304 numColors - numColorsWithAlpha);
305 }
scroggof24f2242015-03-03 08:59:20 -0800306 }
307
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400308 if (this->colorXform() && !this->xformOnDecode()) {
309 this->applyColorXform(colorTable, colorTable, numColors);
msarettdcd5e652016-08-22 08:48:40 -0700310 }
311
msarett13a91232016-02-01 08:03:29 -0800312 // Pad the color table with the last color in the table (or black) in the case that
313 // invalid pixel indices exceed the number of colors in the table.
314 const int maxColors = 1 << fBitDepth;
315 if (numColors < maxColors) {
msarettdcd5e652016-08-22 08:48:40 -0700316 SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK;
317 sk_memset32(colorTable + numColors, lastColor, maxColors - numColors);
scroggof24f2242015-03-03 08:59:20 -0800318 }
319
msarettdcd5e652016-08-22 08:48:40 -0700320 fColorTable.reset(new SkColorTable(colorTable, maxColors));
scroggo05245902015-03-25 11:11:52 -0700321 return true;
scroggof24f2242015-03-03 08:59:20 -0800322}
323
324///////////////////////////////////////////////////////////////////////////////
325// Creation
326///////////////////////////////////////////////////////////////////////////////
327
Leon Scroggins IIIa77f30c2020-03-09 14:23:30 -0400328bool SkPngCodec::IsPng(const void* buf, size_t bytesRead) {
scroggodb30be22015-12-08 18:54:13 -0800329 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
scroggof24f2242015-03-03 08:59:20 -0800330}
331
scroggo8e6c7ad2016-09-16 08:20:38 -0700332#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
333
msarett6a738212016-03-04 13:27:35 -0800334static float png_fixed_point_to_float(png_fixed_point x) {
335 // We multiply by the same factor that libpng used to convert
336 // fixed point -> double. Since we want floats, we choose to
337 // do the conversion ourselves rather than convert
338 // fixed point -> double -> float.
339 return ((float) x) * 0.00001f;
340}
341
msarett128245c2016-03-30 12:01:47 -0700342static float png_inverted_fixed_point_to_float(png_fixed_point x) {
343 // This is necessary because the gAMA chunk actually stores 1/gamma.
344 return 1.0f / png_fixed_point_to_float(x);
345}
346
scroggo8e6c7ad2016-09-16 08:20:38 -0700347#endif // LIBPNG >= 1.6
348
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400349// If there is no color profile information, it will use sRGB.
350std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(png_structp png_ptr,
351 png_infop info_ptr) {
msarett6a738212016-03-04 13:27:35 -0800352
msarette2443222016-03-04 14:20:49 -0800353#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
msarett6a738212016-03-04 13:27:35 -0800354 // First check for an ICC profile
355 png_bytep profile;
356 png_uint_32 length;
357 // The below variables are unused, however, we need to pass them in anyway or
358 // png_get_iCCP() will return nothing.
359 // Could knowing the |name| of the profile ever be interesting? Maybe for debugging?
360 png_charp name;
361 // The |compression| is uninteresting since:
362 // (1) libpng has already decompressed the profile for us.
363 // (2) "deflate" is the only mode of decompression that libpng supports.
364 int compression;
365 if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
366 &length)) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400367 auto data = SkData::MakeWithCopy(profile, length);
368 return SkEncodedInfo::ICCProfile::Make(std::move(data));
msarett6a738212016-03-04 13:27:35 -0800369 }
370
371 // Second, check for sRGB.
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400372 // Note that Blink does this first. This code checks ICC first, with the thinking that
373 // an image has both truly wants the potentially more specific ICC chunk, with sRGB as a
374 // backup in case the decoder does not support full color management.
msarett6a738212016-03-04 13:27:35 -0800375 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
msarett6a738212016-03-04 13:27:35 -0800376 // sRGB chunks also store a rendering intent: Absolute, Relative,
377 // Perceptual, and Saturation.
Leon Scroggins III5dd47e42018-09-27 15:26:48 -0400378 // FIXME (scroggo): Extract this information from the sRGB chunk once
msarett6a738212016-03-04 13:27:35 -0800379 // we are able to handle this information in
Leon Scroggins III5dd47e42018-09-27 15:26:48 -0400380 // skcms_ICCProfile
381 return nullptr;
msarett6a738212016-03-04 13:27:35 -0800382 }
383
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400384 // Default to SRGB gamut.
385 skcms_Matrix3x3 toXYZD50 = skcms_sRGB_profile()->toXYZD50;
msarett6a738212016-03-04 13:27:35 -0800386 // Next, check for chromaticities.
msaretta5a31dd2016-10-11 09:41:16 -0700387 png_fixed_point chrm[8];
msarett6a738212016-03-04 13:27:35 -0800388 png_fixed_point gamma;
msaretta5a31dd2016-10-11 09:41:16 -0700389 if (png_get_cHRM_fixed(png_ptr, info_ptr, &chrm[0], &chrm[1], &chrm[2], &chrm[3], &chrm[4],
390 &chrm[5], &chrm[6], &chrm[7]))
msarett55447952016-07-22 14:07:23 -0700391 {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400392 float rx = png_fixed_point_to_float(chrm[2]);
393 float ry = png_fixed_point_to_float(chrm[3]);
394 float gx = png_fixed_point_to_float(chrm[4]);
395 float gy = png_fixed_point_to_float(chrm[5]);
396 float bx = png_fixed_point_to_float(chrm[6]);
397 float by = png_fixed_point_to_float(chrm[7]);
398 float wx = png_fixed_point_to_float(chrm[0]);
399 float wy = png_fixed_point_to_float(chrm[1]);
msarett55447952016-07-22 14:07:23 -0700400
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400401 skcms_Matrix3x3 tmp;
402 if (skcms_PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, &tmp)) {
403 toXYZD50 = tmp;
404 } else {
405 // Note that Blink simply returns nullptr in this case. We'll fall
406 // back to srgb.
msarett55447952016-07-22 14:07:23 -0700407 }
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400408 }
msarett6a738212016-03-04 13:27:35 -0800409
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400410 skcms_TransferFunction fn;
411 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
412 fn.a = 1.0f;
413 fn.b = fn.c = fn.d = fn.e = fn.f = 0.0f;
414 fn.g = png_inverted_fixed_point_to_float(gamma);
415 } else {
msarettc4ce6b52016-06-16 07:37:41 -0700416 // Default to sRGB gamma if the image has color space information,
417 // but does not specify gamma.
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400418 // Note that Blink would again return nullptr in this case.
419 fn = *skcms_sRGB_TransferFunction();
msarett6a738212016-03-04 13:27:35 -0800420 }
421
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400422 skcms_ICCProfile skcmsProfile;
423 skcms_Init(&skcmsProfile);
424 skcms_SetTransferFunction(&skcmsProfile, &fn);
425 skcms_SetXYZD50(&skcmsProfile, &toXYZD50);
msarett6a738212016-03-04 13:27:35 -0800426
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400427 return SkEncodedInfo::ICCProfile::Make(skcmsProfile);
428#else // LIBPNG >= 1.6
Leon Scroggins III5dd47e42018-09-27 15:26:48 -0400429 return nullptr;
msarette2443222016-03-04 14:20:49 -0800430#endif // LIBPNG >= 1.6
msarett6a738212016-03-04 13:27:35 -0800431}
432
msarett400a93b2016-09-01 18:32:52 -0700433void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
434 switch (fXformMode) {
435 case kSwizzleOnly_XformMode:
msarett400a93b2016-09-01 18:32:52 -0700436 break;
437 case kColorOnly_XformMode:
438 // Intentional fall through. A swizzler hasn't been created yet, but one will
439 // be created later if we are sampling. We'll go ahead and allocate
440 // enough memory to swizzle if necessary.
441 case kSwizzleColor_XformMode: {
Matt Sarett34c69d62017-01-19 17:42:23 -0500442 const int bitsPerPixel = this->getEncodedInfo().bitsPerPixel();
443
444 // If we have more than 8-bits (per component) of precision, we will keep that
445 // extra precision. Otherwise, we will swizzle to RGBA_8888 before transforming.
446 const size_t bytesPerPixel = (bitsPerPixel > 32) ? bitsPerPixel / 8 : 4;
447 const size_t colorXformBytes = dstInfo.width() * bytesPerPixel;
scroggo8e6c7ad2016-09-16 08:20:38 -0700448 fStorage.reset(colorXformBytes);
Matt Sarett379938e2017-01-12 18:34:29 -0500449 fColorXformSrcRow = fStorage.get();
msarett400a93b2016-09-01 18:32:52 -0700450 break;
451 }
452 }
msarettd1ec89b2016-08-03 12:59:27 -0700453}
454
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400455static skcms_PixelFormat png_select_xform_format(const SkEncodedInfo& info) {
Matt Sarett34c69d62017-01-19 17:42:23 -0500456 // We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA.
457 if (16 == info.bitsPerComponent()) {
458 if (SkEncodedInfo::kRGBA_Color == info.color()) {
Mike Klein34e5e1b2018-09-12 16:05:38 -0400459 return skcms_PixelFormat_RGBA_16161616BE;
Matt Sarett34c69d62017-01-19 17:42:23 -0500460 } else if (SkEncodedInfo::kRGB_Color == info.color()) {
Mike Klein34e5e1b2018-09-12 16:05:38 -0400461 return skcms_PixelFormat_RGB_161616BE;
Matt Sarett34c69d62017-01-19 17:42:23 -0500462 }
Brian Osmanb3f38302018-09-07 15:24:44 -0400463 } else if (SkEncodedInfo::kGray_Color == info.color()) {
464 return skcms_PixelFormat_G_8;
Matt Sarett379938e2017-01-12 18:34:29 -0500465 }
466
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400467 return skcms_PixelFormat_RGBA_8888;
Matt Sarett379938e2017-01-12 18:34:29 -0500468}
469
scroggo8e6c7ad2016-09-16 08:20:38 -0700470void SkPngCodec::applyXformRow(void* dst, const void* src) {
msarett400a93b2016-09-01 18:32:52 -0700471 switch (fXformMode) {
472 case kSwizzleOnly_XformMode:
473 fSwizzler->swizzle(dst, (const uint8_t*) src);
474 break;
475 case kColorOnly_XformMode:
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400476 this->applyColorXform(dst, src, fXformWidth);
msarett400a93b2016-09-01 18:32:52 -0700477 break;
478 case kSwizzleColor_XformMode:
479 fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src);
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400480 this->applyColorXform(dst, fColorXformSrcRow, fXformWidth);
msarett400a93b2016-09-01 18:32:52 -0700481 break;
482 }
msarettdcd5e652016-08-22 08:48:40 -0700483}
484
Leon Scroggins III44764002018-11-13 10:26:34 -0500485static SkCodec::Result log_and_return_error(bool success) {
486 if (success) return SkCodec::kIncompleteInput;
487#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
488 SkAndroidFrameworkUtils::SafetyNetLog("117838472");
489#endif
490 return SkCodec::kErrorInInput;
491}
492
scroggo8e6c7ad2016-09-16 08:20:38 -0700493class SkPngNormalDecoder : public SkPngCodec {
scroggo05245902015-03-25 11:11:52 -0700494public:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400495 SkPngNormalDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
496 SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
497 : INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
scroggoff9f7bb2016-10-10 11:35:01 -0700498 , fRowsWrittenToOutput(0)
scroggo8e6c7ad2016-09-16 08:20:38 -0700499 , fDst(nullptr)
500 , fRowBytes(0)
501 , fFirstRow(0)
502 , fLastRow(0)
scroggo1c005e42015-08-04 09:24:45 -0700503 {}
504
scroggo8e6c7ad2016-09-16 08:20:38 -0700505 static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
506 GetDecoder(png_ptr)->allRowsCallback(row, rowNum);
scroggo05245902015-03-25 11:11:52 -0700507 }
508
scroggo8e6c7ad2016-09-16 08:20:38 -0700509 static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
510 GetDecoder(png_ptr)->rowCallback(row, rowNum);
msarettd1ec89b2016-08-03 12:59:27 -0700511 }
512
emmaleer0a4c3cb2015-06-22 10:40:21 -0700513private:
scroggoff9f7bb2016-10-10 11:35:01 -0700514 int fRowsWrittenToOutput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700515 void* fDst;
516 size_t fRowBytes;
517
518 // Variables for partial decode
519 int fFirstRow; // FIXME: Move to baseclass?
520 int fLastRow;
scroggo4f2a88c2016-10-17 14:32:41 -0700521 int fRowsNeeded;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700522
scroggo46c57472015-09-30 08:57:13 -0700523 typedef SkPngCodec INHERITED;
scroggo8e6c7ad2016-09-16 08:20:38 -0700524
525 static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) {
526 return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr));
527 }
528
529 Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
Leon Scroggins III712476e2018-10-03 15:47:00 -0400530 const int height = this->dimensions().height();
Leon Scroggins III83239652017-04-21 13:47:12 -0400531 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, AllRowsCallback, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700532 fDst = dst;
533 fRowBytes = rowBytes;
534
scroggoff9f7bb2016-10-10 11:35:01 -0700535 fRowsWrittenToOutput = 0;
scroggoc46cdd42016-10-10 06:45:32 -0700536 fFirstRow = 0;
537 fLastRow = height - 1;
scroggo8e6c7ad2016-09-16 08:20:38 -0700538
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400539 const bool success = this->processData();
540 if (success && fRowsWrittenToOutput == height) {
541 return kSuccess;
scroggo8e6c7ad2016-09-16 08:20:38 -0700542 }
543
544 if (rowsDecoded) {
scroggoff9f7bb2016-10-10 11:35:01 -0700545 *rowsDecoded = fRowsWrittenToOutput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700546 }
547
Leon Scroggins III44764002018-11-13 10:26:34 -0500548 return log_and_return_error(success);
scroggo8e6c7ad2016-09-16 08:20:38 -0700549 }
550
551 void allRowsCallback(png_bytep row, int rowNum) {
scroggoff9f7bb2016-10-10 11:35:01 -0700552 SkASSERT(rowNum == fRowsWrittenToOutput);
553 fRowsWrittenToOutput++;
scroggo8e6c7ad2016-09-16 08:20:38 -0700554 this->applyXformRow(fDst, row);
555 fDst = SkTAddOffset<void>(fDst, fRowBytes);
556 }
557
558 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
Leon Scroggins III83239652017-04-21 13:47:12 -0400559 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, RowCallback, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700560 fFirstRow = firstRow;
561 fLastRow = lastRow;
562 fDst = dst;
563 fRowBytes = rowBytes;
scroggoff9f7bb2016-10-10 11:35:01 -0700564 fRowsWrittenToOutput = 0;
scroggo4f2a88c2016-10-17 14:32:41 -0700565 fRowsNeeded = fLastRow - fFirstRow + 1;
scroggo8e6c7ad2016-09-16 08:20:38 -0700566 }
567
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400568 Result decode(int* rowsDecoded) override {
scroggo4f2a88c2016-10-17 14:32:41 -0700569 if (this->swizzler()) {
570 const int sampleY = this->swizzler()->sampleY();
571 fRowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
572 }
nagarajan.ndd7ffa52017-09-29 08:23:32 +0530573
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400574 const bool success = this->processData();
575 if (success && fRowsWrittenToOutput == fRowsNeeded) {
576 return kSuccess;
scroggo8e6c7ad2016-09-16 08:20:38 -0700577 }
578
579 if (rowsDecoded) {
scroggoff9f7bb2016-10-10 11:35:01 -0700580 *rowsDecoded = fRowsWrittenToOutput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700581 }
582
Leon Scroggins III44764002018-11-13 10:26:34 -0500583 return log_and_return_error(success);
scroggo8e6c7ad2016-09-16 08:20:38 -0700584 }
585
586 void rowCallback(png_bytep row, int rowNum) {
587 if (rowNum < fFirstRow) {
588 // Ignore this row.
589 return;
590 }
591
592 SkASSERT(rowNum <= fLastRow);
scroggo4f2a88c2016-10-17 14:32:41 -0700593 SkASSERT(fRowsWrittenToOutput < fRowsNeeded);
scroggo8e6c7ad2016-09-16 08:20:38 -0700594
595 // If there is no swizzler, all rows are needed.
scroggo4f2a88c2016-10-17 14:32:41 -0700596 if (!this->swizzler() || this->swizzler()->rowNeeded(rowNum - fFirstRow)) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700597 this->applyXformRow(fDst, row);
598 fDst = SkTAddOffset<void>(fDst, fRowBytes);
scroggoff9f7bb2016-10-10 11:35:01 -0700599 fRowsWrittenToOutput++;
scroggo8e6c7ad2016-09-16 08:20:38 -0700600 }
601
scroggo4f2a88c2016-10-17 14:32:41 -0700602 if (fRowsWrittenToOutput == fRowsNeeded) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700603 // Fake error to stop decoding scanlines.
604 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
605 }
606 }
emmaleer0a4c3cb2015-06-22 10:40:21 -0700607};
608
scroggo8e6c7ad2016-09-16 08:20:38 -0700609class SkPngInterlacedDecoder : public SkPngCodec {
610public:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400611 SkPngInterlacedDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
612 SkPngChunkReader* reader, png_structp png_ptr,
Mike Reedede7bac2017-07-23 15:30:02 -0400613 png_infop info_ptr, int bitDepth, int numberPasses)
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400614 : INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
scroggo8e6c7ad2016-09-16 08:20:38 -0700615 , fNumberPasses(numberPasses)
616 , fFirstRow(0)
617 , fLastRow(0)
618 , fLinesDecoded(0)
619 , fInterlacedComplete(false)
620 , fPng_rowbytes(0)
621 {}
622
623 static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int pass) {
624 auto decoder = static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr));
625 decoder->interlacedRowCallback(row, rowNum, pass);
626 }
627
scroggo8e6c7ad2016-09-16 08:20:38 -0700628private:
629 const int fNumberPasses;
630 int fFirstRow;
631 int fLastRow;
632 void* fDst;
633 size_t fRowBytes;
634 int fLinesDecoded;
635 bool fInterlacedComplete;
636 size_t fPng_rowbytes;
637 SkAutoTMalloc<png_byte> fInterlaceBuffer;
638
639 typedef SkPngCodec INHERITED;
640
scroggo8e6c7ad2016-09-16 08:20:38 -0700641 // FIXME: Currently sharing interlaced callback for all rows and subset. It's not
642 // as expensive as the subset version of non-interlaced, but it still does extra
643 // work.
644 void interlacedRowCallback(png_bytep row, int rowNum, int pass) {
Leon Scroggins III600effb2017-04-24 15:44:45 -0400645 if (rowNum < fFirstRow || rowNum > fLastRow || fInterlacedComplete) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700646 // Ignore this row
647 return;
648 }
649
650 png_bytep oldRow = fInterlaceBuffer.get() + (rowNum - fFirstRow) * fPng_rowbytes;
651 png_progressive_combine_row(this->png_ptr(), oldRow, row);
652
653 if (0 == pass) {
654 // The first pass initializes all rows.
655 SkASSERT(row);
656 SkASSERT(fLinesDecoded == rowNum - fFirstRow);
657 fLinesDecoded++;
658 } else {
659 SkASSERT(fLinesDecoded == fLastRow - fFirstRow + 1);
660 if (fNumberPasses - 1 == pass && rowNum == fLastRow) {
Leon Scroggins III600effb2017-04-24 15:44:45 -0400661 // Last pass, and we have read all of the rows we care about.
scroggo8e6c7ad2016-09-16 08:20:38 -0700662 fInterlacedComplete = true;
Leon Scroggins III712476e2018-10-03 15:47:00 -0400663 if (fLastRow != this->dimensions().height() - 1 ||
Leon Scroggins III600effb2017-04-24 15:44:45 -0400664 (this->swizzler() && this->swizzler()->sampleY() != 1)) {
665 // Fake error to stop decoding scanlines. Only stop if we're not decoding the
666 // whole image, in which case processing the rest of the image might be
667 // expensive. When decoding the whole image, read through the IEND chunk to
668 // preserve Android behavior of leaving the input stream in the right place.
669 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
670 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700671 }
672 }
673 }
674
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400675 Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
Leon Scroggins III712476e2018-10-03 15:47:00 -0400676 const int height = this->dimensions().height();
scroggo8e6c7ad2016-09-16 08:20:38 -0700677 this->setUpInterlaceBuffer(height);
Leon Scroggins III83239652017-04-21 13:47:12 -0400678 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback,
scroggo8e6c7ad2016-09-16 08:20:38 -0700679 nullptr);
680
681 fFirstRow = 0;
682 fLastRow = height - 1;
683 fLinesDecoded = 0;
684
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400685 const bool success = this->processData();
scroggo8e6c7ad2016-09-16 08:20:38 -0700686 png_bytep srcRow = fInterlaceBuffer.get();
687 // FIXME: When resuming, this may rewrite rows that did not change.
688 for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) {
689 this->applyXformRow(dst, srcRow);
690 dst = SkTAddOffset<void>(dst, rowBytes);
691 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes);
692 }
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400693 if (success && fInterlacedComplete) {
694 return kSuccess;
scroggo8e6c7ad2016-09-16 08:20:38 -0700695 }
696
697 if (rowsDecoded) {
698 *rowsDecoded = fLinesDecoded;
699 }
700
Leon Scroggins III44764002018-11-13 10:26:34 -0500701 return log_and_return_error(success);
scroggo8e6c7ad2016-09-16 08:20:38 -0700702 }
703
704 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
705 // FIXME: We could skip rows in the interlace buffer that we won't put in the output.
706 this->setUpInterlaceBuffer(lastRow - firstRow + 1);
Leon Scroggins III83239652017-04-21 13:47:12 -0400707 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700708 fFirstRow = firstRow;
709 fLastRow = lastRow;
710 fDst = dst;
711 fRowBytes = rowBytes;
712 fLinesDecoded = 0;
713 }
714
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400715 Result decode(int* rowsDecoded) override {
716 const bool success = this->processData();
scroggo8e6c7ad2016-09-16 08:20:38 -0700717
718 // Now apply Xforms on all the rows that were decoded.
719 if (!fLinesDecoded) {
scroggoe61b3b42016-10-10 07:17:32 -0700720 if (rowsDecoded) {
721 *rowsDecoded = 0;
722 }
Leon Scroggins III44764002018-11-13 10:26:34 -0500723 return log_and_return_error(success);
scroggo8e6c7ad2016-09-16 08:20:38 -0700724 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700725
scroggo4f2a88c2016-10-17 14:32:41 -0700726 const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1;
727 const int rowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
scroggoff9f7bb2016-10-10 11:35:01 -0700728
scroggo8e6c7ad2016-09-16 08:20:38 -0700729 // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it
730 // may be too tricky/expensive to handle that correctly.
scroggoe9ea3492016-10-18 09:14:11 -0700731
732 // Offset srcRow by get_start_coord rows. We do not need to account for fFirstRow,
733 // since the first row in fInterlaceBuffer corresponds to fFirstRow.
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400734 int srcRow = get_start_coord(sampleY);
scroggo8e6c7ad2016-09-16 08:20:38 -0700735 void* dst = fDst;
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400736 int rowsWrittenToOutput = 0;
737 while (rowsWrittenToOutput < rowsNeeded && srcRow < fLinesDecoded) {
738 png_bytep src = SkTAddOffset<png_byte>(fInterlaceBuffer.get(), fPng_rowbytes * srcRow);
739 this->applyXformRow(dst, src);
scroggo8e6c7ad2016-09-16 08:20:38 -0700740 dst = SkTAddOffset<void>(dst, fRowBytes);
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400741
742 rowsWrittenToOutput++;
743 srcRow += sampleY;
scroggo8e6c7ad2016-09-16 08:20:38 -0700744 }
745
Leon Scroggins III6e45ce72018-10-16 15:29:11 -0400746 if (success && fInterlacedComplete) {
747 return kSuccess;
scroggo8e6c7ad2016-09-16 08:20:38 -0700748 }
749
750 if (rowsDecoded) {
scroggoff9f7bb2016-10-10 11:35:01 -0700751 *rowsDecoded = rowsWrittenToOutput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700752 }
Leon Scroggins III44764002018-11-13 10:26:34 -0500753 return log_and_return_error(success);
scroggo8e6c7ad2016-09-16 08:20:38 -0700754 }
755
756 void setUpInterlaceBuffer(int height) {
757 fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr());
758 fInterlaceBuffer.reset(fPng_rowbytes * height);
759 fInterlacedComplete = false;
760 }
761};
762
msarettac6c7502016-04-25 09:30:24 -0700763// Reads the header and initializes the output fields, if not NULL.
764//
765// @param stream Input data. Will be read to get enough information to properly
766// setup the codec.
767// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
768// If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
769// expected to continue to own it for the lifetime of the png_ptr.
770// @param outCodec Optional output variable. If non-NULL, will be set to a new
771// SkPngCodec on success.
772// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
773// png_structp on success.
774// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
775// png_infop on success;
Leon Scroggins III588fb042017-07-14 16:32:31 -0400776// @return if kSuccess, the caller is responsible for calling
msarettac6c7502016-04-25 09:30:24 -0700777// png_destroy_read_struct(png_ptrp, info_ptrp).
Leon Scroggins III588fb042017-07-14 16:32:31 -0400778// Otherwise, the passed in fields (except stream) are unchanged.
779static SkCodec::Result read_header(SkStream* stream, SkPngChunkReader* chunkReader,
780 SkCodec** outCodec,
781 png_structp* png_ptrp, png_infop* info_ptrp) {
msarettac6c7502016-04-25 09:30:24 -0700782 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
783 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
784 sk_error_fn, sk_warning_fn);
785 if (!png_ptr) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400786 return SkCodec::kInternalError;
msarettac6c7502016-04-25 09:30:24 -0700787 }
788
Leon Scroggins III9b1a8862018-03-01 15:57:32 -0500789#ifdef PNG_SET_OPTION_SUPPORTED
Leon Scroggins III9e8a5942018-02-28 16:24:18 -0500790 // This setting ensures that we display images with incorrect CMF bytes.
791 // See crbug.com/807324.
792 png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
Leon Scroggins III9b1a8862018-03-01 15:57:32 -0500793#endif
Leon Scroggins III9e8a5942018-02-28 16:24:18 -0500794
scroggo8e6c7ad2016-09-16 08:20:38 -0700795 AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec);
msarettac6c7502016-04-25 09:30:24 -0700796
797 png_infop info_ptr = png_create_info_struct(png_ptr);
798 if (info_ptr == nullptr) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400799 return SkCodec::kInternalError;
msarettac6c7502016-04-25 09:30:24 -0700800 }
801
802 autoClean.setInfoPtr(info_ptr);
803
scroggo8e6c7ad2016-09-16 08:20:38 -0700804 if (setjmp(PNG_JMPBUF(png_ptr))) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400805 return SkCodec::kInvalidInput;
msarettac6c7502016-04-25 09:30:24 -0700806 }
807
msarettac6c7502016-04-25 09:30:24 -0700808#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
809 // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
810 // This needs to be installed before we read the png header. Android may store ninepatch
811 // chunks in the header.
812 if (chunkReader) {
813 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
814 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
815 }
816#endif
817
scroggo8e6c7ad2016-09-16 08:20:38 -0700818 const bool decodedBounds = autoClean.decodeBounds();
819
820 if (!decodedBounds) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400821 return SkCodec::kIncompleteInput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700822 }
823
824 // On success, decodeBounds releases ownership of png_ptr and info_ptr.
825 if (png_ptrp) {
826 *png_ptrp = png_ptr;
827 }
828 if (info_ptrp) {
829 *info_ptrp = info_ptr;
830 }
831
832 // decodeBounds takes care of setting outCodec
833 if (outCodec) {
834 SkASSERT(*outCodec);
835 }
Leon Scroggins III588fb042017-07-14 16:32:31 -0400836 return SkCodec::kSuccess;
scroggo8e6c7ad2016-09-16 08:20:38 -0700837}
838
Leon Scroggins III83239652017-04-21 13:47:12 -0400839void AutoCleanPng::infoCallback(size_t idatLength) {
msarettac6c7502016-04-25 09:30:24 -0700840 png_uint_32 origWidth, origHeight;
841 int bitDepth, encodedColorType;
Leon Scroggins III83239652017-04-21 13:47:12 -0400842 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth,
msarettac6c7502016-04-25 09:30:24 -0700843 &encodedColorType, nullptr, nullptr, nullptr);
844
Matt Sarett7a1cc672016-12-14 11:48:31 -0500845 // TODO: Should we support 16-bits of precision for gray images?
846 if (bitDepth == 16 && (PNG_COLOR_TYPE_GRAY == encodedColorType ||
847 PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType)) {
848 bitDepth = 8;
Leon Scroggins III83239652017-04-21 13:47:12 -0400849 png_set_strip_16(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700850 }
851
852 // Now determine the default colorType and alphaType and set the required transforms.
853 // Often, we depend on SkSwizzler to perform any transforms that we need. However, we
854 // still depend on libpng for many of the rare and PNG-specific cases.
855 SkEncodedInfo::Color color;
856 SkEncodedInfo::Alpha alpha;
857 switch (encodedColorType) {
858 case PNG_COLOR_TYPE_PALETTE:
859 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
860 // byte into separate bytes (useful for paletted and grayscale images).
861 if (bitDepth < 8) {
862 // TODO: Should we use SkSwizzler here?
Matt Sarett7a1cc672016-12-14 11:48:31 -0500863 bitDepth = 8;
Leon Scroggins III83239652017-04-21 13:47:12 -0400864 png_set_packing(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700865 }
866
867 color = SkEncodedInfo::kPalette_Color;
868 // Set the alpha depending on if a transparency chunk exists.
Leon Scroggins III83239652017-04-21 13:47:12 -0400869 alpha = png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS) ?
msarettac6c7502016-04-25 09:30:24 -0700870 SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha;
871 break;
872 case PNG_COLOR_TYPE_RGB:
Leon Scroggins III83239652017-04-21 13:47:12 -0400873 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
msarettac6c7502016-04-25 09:30:24 -0700874 // Convert to RGBA if transparency chunk exists.
Leon Scroggins III83239652017-04-21 13:47:12 -0400875 png_set_tRNS_to_alpha(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700876 color = SkEncodedInfo::kRGBA_Color;
877 alpha = SkEncodedInfo::kBinary_Alpha;
878 } else {
879 color = SkEncodedInfo::kRGB_Color;
880 alpha = SkEncodedInfo::kOpaque_Alpha;
881 }
882 break;
883 case PNG_COLOR_TYPE_GRAY:
884 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
885 if (bitDepth < 8) {
886 // TODO: Should we use SkSwizzler here?
Matt Sarett7a1cc672016-12-14 11:48:31 -0500887 bitDepth = 8;
Leon Scroggins III83239652017-04-21 13:47:12 -0400888 png_set_expand_gray_1_2_4_to_8(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700889 }
890
Leon Scroggins III83239652017-04-21 13:47:12 -0400891 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
892 png_set_tRNS_to_alpha(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700893 color = SkEncodedInfo::kGrayAlpha_Color;
894 alpha = SkEncodedInfo::kBinary_Alpha;
895 } else {
896 color = SkEncodedInfo::kGray_Color;
897 alpha = SkEncodedInfo::kOpaque_Alpha;
898 }
899 break;
900 case PNG_COLOR_TYPE_GRAY_ALPHA:
901 color = SkEncodedInfo::kGrayAlpha_Color;
902 alpha = SkEncodedInfo::kUnpremul_Alpha;
903 break;
904 case PNG_COLOR_TYPE_RGBA:
905 color = SkEncodedInfo::kRGBA_Color;
906 alpha = SkEncodedInfo::kUnpremul_Alpha;
907 break;
908 default:
909 // All the color types have been covered above.
910 SkASSERT(false);
911 color = SkEncodedInfo::kRGBA_Color;
912 alpha = SkEncodedInfo::kUnpremul_Alpha;
913 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700914
915 const int numberPasses = png_set_interlace_handling(fPng_ptr);
916
scroggo8e6c7ad2016-09-16 08:20:38 -0700917 if (fOutCodec) {
918 SkASSERT(nullptr == *fOutCodec);
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400919 auto profile = read_color_profile(fPng_ptr, fInfo_ptr);
920 if (profile) {
921 switch (profile->profile()->data_color_space) {
922 case skcms_Signature_CMYK:
923 profile = nullptr;
Leon Scroggins IIIf78b55c2017-10-31 13:49:14 -0400924 break;
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400925 case skcms_Signature_Gray:
Leon Scroggins IIIf78b55c2017-10-31 13:49:14 -0400926 if (SkEncodedInfo::kGray_Color != color &&
927 SkEncodedInfo::kGrayAlpha_Color != color)
928 {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400929 profile = nullptr;
Leon Scroggins IIIf78b55c2017-10-31 13:49:14 -0400930 }
931 break;
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400932 default:
Leon Scroggins IIIf78b55c2017-10-31 13:49:14 -0400933 break;
934 }
Matt Sarett523116d2017-01-12 18:36:38 -0500935 }
scroggod8d68552016-06-06 11:26:17 -0700936
Mike Reedd6cb11e2017-11-30 15:33:04 -0500937 if (encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
938 png_color_8p sigBits;
939 if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
940 if (8 == sigBits->alpha && kGraySigBit_GrayAlphaIsJustAlpha == sigBits->gray) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400941 color = SkEncodedInfo::kXAlpha_Color;
Mike Reedd6cb11e2017-11-30 15:33:04 -0500942 }
943 }
944 } else if (SkEncodedInfo::kOpaque_Alpha == alpha) {
msarett549ca322016-08-17 08:54:08 -0700945 png_color_8p sigBits;
scroggo8e6c7ad2016-09-16 08:20:38 -0700946 if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
msarett549ca322016-08-17 08:54:08 -0700947 if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
948 // Recommend a decode to 565 if the sBIT indicates 565.
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400949 color = SkEncodedInfo::k565_Color;
msarett549ca322016-08-17 08:54:08 -0700950 }
951 }
952 }
scroggod8d68552016-06-06 11:26:17 -0700953
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400954 SkEncodedInfo encodedInfo = SkEncodedInfo::Make(origWidth, origHeight, color, alpha,
955 bitDepth, std::move(profile));
msarettac6c7502016-04-25 09:30:24 -0700956 if (1 == numberPasses) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400957 *fOutCodec = new SkPngNormalDecoder(std::move(encodedInfo),
Mike Reedede7bac2017-07-23 15:30:02 -0400958 std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth);
msarettac6c7502016-04-25 09:30:24 -0700959 } else {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400960 *fOutCodec = new SkPngInterlacedDecoder(std::move(encodedInfo),
Mike Reedede7bac2017-07-23 15:30:02 -0400961 std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth,
962 numberPasses);
msarettac6c7502016-04-25 09:30:24 -0700963 }
Leon Scroggins III83239652017-04-21 13:47:12 -0400964 static_cast<SkPngCodec*>(*fOutCodec)->setIdatLength(idatLength);
msarettac6c7502016-04-25 09:30:24 -0700965 }
966
scroggo8e6c7ad2016-09-16 08:20:38 -0700967 // Release the pointers, which are now owned by the codec or the caller is expected to
968 // take ownership.
969 this->releasePngPtrs();
msarettac6c7502016-04-25 09:30:24 -0700970}
971
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400972SkPngCodec::SkPngCodec(SkEncodedInfo&& encodedInfo, std::unique_ptr<SkStream> stream,
973 SkPngChunkReader* chunkReader, void* png_ptr, void* info_ptr, int bitDepth)
974 : INHERITED(std::move(encodedInfo), png_select_xform_format(encodedInfo), std::move(stream))
msarettac6c7502016-04-25 09:30:24 -0700975 , fPngChunkReader(SkSafeRef(chunkReader))
976 , fPng_ptr(png_ptr)
977 , fInfo_ptr(info_ptr)
msarettd1ec89b2016-08-03 12:59:27 -0700978 , fColorXformSrcRow(nullptr)
msarettac6c7502016-04-25 09:30:24 -0700979 , fBitDepth(bitDepth)
Leon Scroggins III83239652017-04-21 13:47:12 -0400980 , fIdatLength(0)
981 , fDecodedIdat(false)
msarettac6c7502016-04-25 09:30:24 -0700982{}
983
984SkPngCodec::~SkPngCodec() {
985 this->destroyReadStruct();
986}
987
988void SkPngCodec::destroyReadStruct() {
989 if (fPng_ptr) {
990 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
991 SkASSERT(fInfo_ptr);
mtklein6dc5b9a2016-08-24 12:22:32 -0700992 png_destroy_read_struct((png_struct**)&fPng_ptr, (png_info**)&fInfo_ptr, nullptr);
msarettac6c7502016-04-25 09:30:24 -0700993 fPng_ptr = nullptr;
994 fInfo_ptr = nullptr;
995 }
996}
997
998///////////////////////////////////////////////////////////////////////////////
999// Getting the pixels
1000///////////////////////////////////////////////////////////////////////////////
1001
Leon Scroggins571b30f2017-07-11 17:35:31 +00001002SkCodec::Result SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options) {
scroggo8e6c7ad2016-09-16 08:20:38 -07001003 if (setjmp(PNG_JMPBUF((png_struct*)fPng_ptr))) {
msarettd1ec89b2016-08-03 12:59:27 -07001004 SkCodecPrintf("Failed on png_read_update_info.\n");
Matt Sarettd59948a2017-04-26 10:59:48 -04001005 return kInvalidInput;
msarettac6c7502016-04-25 09:30:24 -07001006 }
1007 png_read_update_info(fPng_ptr, fInfo_ptr);
1008
Matt Sarett313c4632016-10-20 12:35:23 -04001009 // Reset fSwizzler and this->colorXform(). We can't do this in onRewind() because the
msarett400a93b2016-09-01 18:32:52 -07001010 // interlaced scanline decoder may need to rewind.
1011 fSwizzler.reset(nullptr);
msarett400a93b2016-09-01 18:32:52 -07001012
Brian Osman5ea41fc2018-09-26 18:49:27 +00001013 // If skcms directly supports the encoded PNG format, we should skip format
Matt Sarett34c69d62017-01-19 17:42:23 -05001014 // conversion in the swizzler (or skip swizzling altogether).
1015 bool skipFormatConversion = false;
1016 switch (this->getEncodedInfo().color()) {
1017 case SkEncodedInfo::kRGB_Color:
1018 if (this->getEncodedInfo().bitsPerComponent() != 16) {
1019 break;
1020 }
John Stiles30212b72020-06-11 17:55:07 -04001021 [[fallthrough]];
Matt Sarett34c69d62017-01-19 17:42:23 -05001022 case SkEncodedInfo::kRGBA_Color:
Brian Osmanb3f38302018-09-07 15:24:44 -04001023 case SkEncodedInfo::kGray_Color:
Matt Sarett34c69d62017-01-19 17:42:23 -05001024 skipFormatConversion = this->colorXform();
1025 break;
1026 default:
1027 break;
1028 }
Matt Sarett379938e2017-01-12 18:34:29 -05001029 if (skipFormatConversion && !options.fSubset) {
msarett400a93b2016-09-01 18:32:52 -07001030 fXformMode = kColorOnly_XformMode;
Matt Sarettd59948a2017-04-26 10:59:48 -04001031 return kSuccess;
msarettd1ec89b2016-08-03 12:59:27 -07001032 }
1033
msarettac6c7502016-04-25 09:30:24 -07001034 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
Leon Scroggins571b30f2017-07-11 17:35:31 +00001035 if (!this->createColorTable(dstInfo)) {
Matt Sarettd59948a2017-04-26 10:59:48 -04001036 return kInvalidInput;
msarettac6c7502016-04-25 09:30:24 -07001037 }
1038 }
1039
Matt Sarett379938e2017-01-12 18:34:29 -05001040 this->initializeSwizzler(dstInfo, options, skipFormatConversion);
Matt Sarettd59948a2017-04-26 10:59:48 -04001041 return kSuccess;
msarett400a93b2016-09-01 18:32:52 -07001042}
1043
msarettc0444612016-09-16 11:45:58 -07001044void SkPngCodec::initializeXformParams() {
1045 switch (fXformMode) {
1046 case kColorOnly_XformMode:
msarettc0444612016-09-16 11:45:58 -07001047 fXformWidth = this->dstInfo().width();
1048 break;
1049 case kSwizzleColor_XformMode:
msarettc0444612016-09-16 11:45:58 -07001050 fXformWidth = this->swizzler()->swizzleWidth();
1051 break;
1052 default:
1053 break;
1054 }
scroggo8e6c7ad2016-09-16 08:20:38 -07001055}
1056
Matt Sarett379938e2017-01-12 18:34:29 -05001057void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
1058 bool skipFormatConversion) {
msarett400a93b2016-09-01 18:32:52 -07001059 SkImageInfo swizzlerInfo = dstInfo;
1060 Options swizzlerOptions = options;
1061 fXformMode = kSwizzleOnly_XformMode;
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -04001062 if (this->colorXform() && this->xformOnDecode()) {
Brian Osmanb3f38302018-09-07 15:24:44 -04001063 if (SkEncodedInfo::kGray_Color == this->getEncodedInfo().color()) {
1064 swizzlerInfo = swizzlerInfo.makeColorType(kGray_8_SkColorType);
1065 } else {
1066 swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType);
1067 }
msarett400a93b2016-09-01 18:32:52 -07001068 if (kPremul_SkAlphaType == dstInfo.alphaType()) {
1069 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
1070 }
1071
1072 fXformMode = kSwizzleColor_XformMode;
1073
1074 // Here, we swizzle into temporary memory, which is not zero initialized.
1075 // FIXME (msarett):
1076 // Is this a problem?
1077 swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized;
1078 }
1079
Leon Scroggins III65f4aea2018-10-24 12:17:22 -04001080 if (skipFormatConversion) {
1081 // We cannot skip format conversion when there is a color table.
1082 SkASSERT(!fColorTable);
1083 int srcBPP = 0;
1084 switch (this->getEncodedInfo().color()) {
1085 case SkEncodedInfo::kRGB_Color:
1086 SkASSERT(this->getEncodedInfo().bitsPerComponent() == 16);
1087 srcBPP = 6;
1088 break;
1089 case SkEncodedInfo::kRGBA_Color:
1090 srcBPP = this->getEncodedInfo().bitsPerComponent() / 2;
1091 break;
1092 case SkEncodedInfo::kGray_Color:
1093 srcBPP = 1;
1094 break;
1095 default:
1096 SkASSERT(false);
1097 break;
1098 }
1099 fSwizzler = SkSwizzler::MakeSimple(srcBPP, swizzlerInfo, swizzlerOptions);
1100 } else {
1101 const SkPMColor* colors = get_color_ptr(fColorTable.get());
1102 fSwizzler = SkSwizzler::Make(this->getEncodedInfo(), colors, swizzlerInfo,
1103 swizzlerOptions);
1104 }
msarettac6c7502016-04-25 09:30:24 -07001105 SkASSERT(fSwizzler);
msarett400a93b2016-09-01 18:32:52 -07001106}
1107
1108SkSampler* SkPngCodec::getSampler(bool createIfNecessary) {
1109 if (fSwizzler || !createIfNecessary) {
Ben Wagner145dbcd2016-11-03 14:40:50 -04001110 return fSwizzler.get();
msarett400a93b2016-09-01 18:32:52 -07001111 }
1112
Matt Sarett379938e2017-01-12 18:34:29 -05001113 this->initializeSwizzler(this->dstInfo(), this->options(), true);
Ben Wagner145dbcd2016-11-03 14:40:50 -04001114 return fSwizzler.get();
msarettac6c7502016-04-25 09:30:24 -07001115}
1116
msarettac6c7502016-04-25 09:30:24 -07001117bool SkPngCodec::onRewind() {
1118 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
1119 // succeeds, they will be repopulated, and if it fails, they will
1120 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
1121 // come through this function which will rewind and again attempt
1122 // to reinitialize them.
1123 this->destroyReadStruct();
1124
scroggo46c57472015-09-30 08:57:13 -07001125 png_structp png_ptr;
1126 png_infop info_ptr;
Leon Scroggins III588fb042017-07-14 16:32:31 -04001127 if (kSuccess != read_header(this->stream(), fPngChunkReader.get(), nullptr,
1128 &png_ptr, &info_ptr)) {
msarettac6c7502016-04-25 09:30:24 -07001129 return false;
scroggo05245902015-03-25 11:11:52 -07001130 }
1131
msarettac6c7502016-04-25 09:30:24 -07001132 fPng_ptr = png_ptr;
1133 fInfo_ptr = info_ptr;
Leon Scroggins III83239652017-04-21 13:47:12 -04001134 fDecodedIdat = false;
msarettac6c7502016-04-25 09:30:24 -07001135 return true;
1136}
msarett6a738212016-03-04 13:27:35 -08001137
msarettd1ec89b2016-08-03 12:59:27 -07001138SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
1139 size_t rowBytes, const Options& options,
msarettac6c7502016-04-25 09:30:24 -07001140 int* rowsDecoded) {
Leon Scroggins571b30f2017-07-11 17:35:31 +00001141 Result result = this->initializeXforms(dstInfo, options);
Matt Sarettd59948a2017-04-26 10:59:48 -04001142 if (kSuccess != result) {
1143 return result;
1144 }
1145
msarettac6c7502016-04-25 09:30:24 -07001146 if (options.fSubset) {
msarettac6c7502016-04-25 09:30:24 -07001147 return kUnimplemented;
scroggo05245902015-03-25 11:11:52 -07001148 }
1149
msarett400a93b2016-09-01 18:32:52 -07001150 this->allocateStorage(dstInfo);
msarettc0444612016-09-16 11:45:58 -07001151 this->initializeXformParams();
scroggo8e6c7ad2016-09-16 08:20:38 -07001152 return this->decodeAllRows(dst, rowBytes, rowsDecoded);
1153}
msarettac6c7502016-04-25 09:30:24 -07001154
scroggo8e6c7ad2016-09-16 08:20:38 -07001155SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
Leon Scroggins571b30f2017-07-11 17:35:31 +00001156 void* dst, size_t rowBytes, const SkCodec::Options& options) {
Leon Scroggins571b30f2017-07-11 17:35:31 +00001157 Result result = this->initializeXforms(dstInfo, options);
Matt Sarettd59948a2017-04-26 10:59:48 -04001158 if (kSuccess != result) {
1159 return result;
1160 }
1161
scroggo8e6c7ad2016-09-16 08:20:38 -07001162 this->allocateStorage(dstInfo);
1163
1164 int firstRow, lastRow;
1165 if (options.fSubset) {
1166 firstRow = options.fSubset->top();
1167 lastRow = options.fSubset->bottom() - 1;
1168 } else {
1169 firstRow = 0;
1170 lastRow = dstInfo.height() - 1;
1171 }
1172 this->setRange(firstRow, lastRow, dst, rowBytes);
scroggod8d68552016-06-06 11:26:17 -07001173 return kSuccess;
scroggo6fb23912016-06-02 14:16:43 -07001174}
1175
scroggo8e6c7ad2016-09-16 08:20:38 -07001176SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) {
1177 // FIXME: Only necessary on the first call.
msarettc0444612016-09-16 11:45:58 -07001178 this->initializeXformParams();
scroggo8e6c7ad2016-09-16 08:20:38 -07001179
1180 return this->decode(rowsDecoded);
1181}
1182
Mike Reedede7bac2017-07-23 15:30:02 -04001183std::unique_ptr<SkCodec> SkPngCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
1184 Result* result, SkPngChunkReader* chunkReader) {
scroggo8e6c7ad2016-09-16 08:20:38 -07001185 SkCodec* outCodec = nullptr;
Mike Reedede7bac2017-07-23 15:30:02 -04001186 *result = read_header(stream.get(), chunkReader, &outCodec, nullptr, nullptr);
Leon Scroggins III588fb042017-07-14 16:32:31 -04001187 if (kSuccess == *result) {
msarettac6c7502016-04-25 09:30:24 -07001188 // Codec has taken ownership of the stream.
1189 SkASSERT(outCodec);
Mike Reedede7bac2017-07-23 15:30:02 -04001190 stream.release();
msarettac6c7502016-04-25 09:30:24 -07001191 }
Mike Reedede7bac2017-07-23 15:30:02 -04001192 return std::unique_ptr<SkCodec>(outCodec);
scroggo05245902015-03-25 11:11:52 -07001193}