blob: 9691f12d4d6b210245d1a0992b5853a20b5fb3cc [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
msarett74114382015-03-16 11:55:18 -07008#include "SkCodecPriv.h"
scroggof24f2242015-03-03 08:59:20 -08009#include "SkColorPriv.h"
10#include "SkColorTable.h"
11#include "SkBitmap.h"
12#include "SkMath.h"
msarettbe1d5552016-01-21 09:05:23 -080013#include "SkPngCodec.h"
mtklein372d65c2016-01-27 13:01:41 -080014#include "SkPngFilters.h"
scroggof24f2242015-03-03 08:59:20 -080015#include "SkSize.h"
16#include "SkStream.h"
17#include "SkSwizzler.h"
scroggo565901d2015-12-10 10:44:13 -080018#include "SkTemplates.h"
scroggof24f2242015-03-03 08:59:20 -080019
mtklein372d65c2016-01-27 13:01:41 -080020#if defined(__SSE2__)
21 #include "pngstruct.h"
22
23 extern "C" void sk_png_init_filter_functions_sse2(png_structp png, unsigned int bpp) {
24 if (bpp == 3) {
25 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub3_sse2;
26 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg3_sse2;
27 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth3_sse2;
28 }
29 if (bpp == 4) {
30 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub4_sse2;
31 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg4_sse2;
32 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth4_sse2;
33 }
34 }
35#endif
36
scroggof24f2242015-03-03 08:59:20 -080037///////////////////////////////////////////////////////////////////////////////
38// Helper macros
39///////////////////////////////////////////////////////////////////////////////
40
41#ifndef png_jmpbuf
42# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
43#endif
44
45/* These were dropped in libpng >= 1.4 */
46#ifndef png_infopp_NULL
halcanary96fcdcc2015-08-27 07:41:13 -070047 #define png_infopp_NULL nullptr
scroggof24f2242015-03-03 08:59:20 -080048#endif
49
50#ifndef png_bytepp_NULL
halcanary96fcdcc2015-08-27 07:41:13 -070051 #define png_bytepp_NULL nullptr
scroggof24f2242015-03-03 08:59:20 -080052#endif
53
54#ifndef int_p_NULL
halcanary96fcdcc2015-08-27 07:41:13 -070055 #define int_p_NULL nullptr
scroggof24f2242015-03-03 08:59:20 -080056#endif
57
58#ifndef png_flush_ptr_NULL
halcanary96fcdcc2015-08-27 07:41:13 -070059 #define png_flush_ptr_NULL nullptr
scroggof24f2242015-03-03 08:59:20 -080060#endif
61
62///////////////////////////////////////////////////////////////////////////////
63// Callback functions
64///////////////////////////////////////////////////////////////////////////////
65
66static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
scroggo230d4ac2015-03-26 07:15:55 -070067 SkCodecPrintf("------ png error %s\n", msg);
scroggof24f2242015-03-03 08:59:20 -080068 longjmp(png_jmpbuf(png_ptr), 1);
69}
70
scroggo0eed6df2015-03-26 10:07:56 -070071void sk_warning_fn(png_structp, png_const_charp msg) {
72 SkCodecPrintf("----- png warning %s\n", msg);
73}
74
scroggof24f2242015-03-03 08:59:20 -080075static void sk_read_fn(png_structp png_ptr, png_bytep data,
76 png_size_t length) {
77 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr));
78 const size_t bytes = stream->read(data, length);
79 if (bytes != length) {
80 // FIXME: We want to report the fact that the stream was truncated.
81 // One way to do that might be to pass a enum to longjmp so setjmp can
82 // specify the failure.
83 png_error(png_ptr, "Read Error!");
84 }
85}
86
scroggocf98fa92015-11-23 08:14:40 -080087#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
88static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
89 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
90 // readChunk() returning true means continue decoding
91 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1;
92}
93#endif
94
scroggof24f2242015-03-03 08:59:20 -080095///////////////////////////////////////////////////////////////////////////////
96// Helpers
97///////////////////////////////////////////////////////////////////////////////
98
99class AutoCleanPng : public SkNoncopyable {
100public:
101 AutoCleanPng(png_structp png_ptr)
102 : fPng_ptr(png_ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700103 , fInfo_ptr(nullptr) {}
scroggof24f2242015-03-03 08:59:20 -0800104
105 ~AutoCleanPng() {
halcanary96fcdcc2015-08-27 07:41:13 -0700106 // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
scroggof24f2242015-03-03 08:59:20 -0800107 if (fPng_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700108 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
scroggof24f2242015-03-03 08:59:20 -0800109 png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL);
110 }
111 }
112
113 void setInfoPtr(png_infop info_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700114 SkASSERT(nullptr == fInfo_ptr);
scroggof24f2242015-03-03 08:59:20 -0800115 fInfo_ptr = info_ptr;
116 }
117
118 void detach() {
halcanary96fcdcc2015-08-27 07:41:13 -0700119 fPng_ptr = nullptr;
120 fInfo_ptr = nullptr;
scroggof24f2242015-03-03 08:59:20 -0800121 }
122
123private:
124 png_structp fPng_ptr;
125 png_infop fInfo_ptr;
126};
127#define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
128
emmaleer21cea722015-07-10 07:48:03 -0700129//checks if there is transparency info in the tRNS chunk
130//image types which could have data in the tRNS chunk include: Index8, Gray8, RGB
131static bool has_transparency_in_tRNS(png_structp png_ptr,
scroggof24f2242015-03-03 08:59:20 -0800132 png_infop info_ptr) {
133 if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
134 return false;
135 }
136
137 png_bytep trans;
138 int num_trans;
halcanary96fcdcc2015-08-27 07:41:13 -0700139 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr);
scroggof24f2242015-03-03 08:59:20 -0800140 return num_trans > 0;
141}
142
143// Method for coverting to either an SkPMColor or a similarly packed
144// unpremultiplied color.
145typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
146
147// Note: SkColorTable claims to store SkPMColors, which is not necessarily
148// the case here.
scroggo9b2cdbf2015-07-10 12:07:02 -0700149bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) {
scroggof24f2242015-03-03 08:59:20 -0800150 int numPalette;
151 png_colorp palette;
152 png_bytep trans;
153
scroggo05245902015-03-25 11:11:52 -0700154 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) {
155 return false;
scroggof24f2242015-03-03 08:59:20 -0800156 }
157
msarett438b2ad2015-04-09 12:43:10 -0700158 // Note: These are not necessarily SkPMColors
scroggof24f2242015-03-03 08:59:20 -0800159 SkPMColor colorStorage[256]; // worst-case storage
160 SkPMColor* colorPtr = colorStorage;
161
162 int numTrans;
scroggo05245902015-03-25 11:11:52 -0700163 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700164 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, nullptr);
scroggof24f2242015-03-03 08:59:20 -0800165 } else {
166 numTrans = 0;
167 }
168
169 // check for bad images that might make us crash
170 if (numTrans > numPalette) {
171 numTrans = numPalette;
172 }
173
174 int index = 0;
scroggof24f2242015-03-03 08:59:20 -0800175
176 // Choose which function to use to create the color table. If the final destination's
177 // colortype is unpremultiplied, the color table will store unpremultiplied colors.
178 PackColorProc proc;
179 if (premultiply) {
180 proc = &SkPreMultiplyARGB;
181 } else {
182 proc = &SkPackARGB32NoCheck;
183 }
184 for (; index < numTrans; index++) {
scroggof24f2242015-03-03 08:59:20 -0800185 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
186 palette++;
187 }
188
scroggof24f2242015-03-03 08:59:20 -0800189 for (; index < numPalette; index++) {
190 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
191 palette++;
192 }
193
msarett438b2ad2015-04-09 12:43:10 -0700194 /* BUGGY IMAGE WORKAROUND
195 Invalid images could contain pixel values that are greater than the number of palette
196 entries. Since we use pixel values as indices into the palette this could result in reading
197 beyond the end of the palette which could leak the contents of uninitialized memory. To
198 ensure this doesn't happen, we grow the colortable to the maximum size that can be
199 addressed by the bitdepth of the image and fill it with the last palette color or black if
200 the palette is empty (really broken image).
201 */
scroggo9b2cdbf2015-07-10 12:07:02 -0700202 int colorCount = SkTMax(numPalette, 1 << SkTMin(fBitDepth, 8));
msarett438b2ad2015-04-09 12:43:10 -0700203 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0);
204 for (; index < colorCount; index++) {
205 *colorPtr++ = lastColor;
206 }
207
208 // Set the new color count
halcanary96fcdcc2015-08-27 07:41:13 -0700209 if (ctableCount != nullptr) {
msarett438b2ad2015-04-09 12:43:10 -0700210 *ctableCount = colorCount;
scroggof24f2242015-03-03 08:59:20 -0800211 }
212
halcanary385fe4d2015-08-26 13:07:48 -0700213 fColorTable.reset(new SkColorTable(colorStorage, colorCount));
scroggo05245902015-03-25 11:11:52 -0700214 return true;
scroggof24f2242015-03-03 08:59:20 -0800215}
216
217///////////////////////////////////////////////////////////////////////////////
218// Creation
219///////////////////////////////////////////////////////////////////////////////
220
scroggodb30be22015-12-08 18:54:13 -0800221bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
222 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
scroggof24f2242015-03-03 08:59:20 -0800223}
224
scroggocf98fa92015-11-23 08:14:40 -0800225// Reads the header and initializes the output fields, if not NULL.
226//
227// @param stream Input data. Will be read to get enough information to properly
228// setup the codec.
229// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
230// If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
231// expected to continue to own it for the lifetime of the png_ptr.
232// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
233// png_structp on success.
234// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
235// png_infop on success;
236// @param imageInfo Optional output variable. If non-NULL, will be set to
237// reflect the properties of the encoded image on success.
238// @param bitDepthPtr Optional output variable. If non-NULL, will be set to the
239// bit depth of the encoded image on success.
240// @param numberPassesPtr Optional output variable. If non-NULL, will be set to
241// the number_passes of the encoded image on success.
242// @return true on success, in which case the caller is responsible for calling
243// png_destroy_read_struct(png_ptrp, info_ptrp).
244// If it returns false, the passed in fields (except stream) are unchanged.
245static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
246 png_structp* png_ptrp, png_infop* info_ptrp,
247 SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPassesPtr) {
scroggof24f2242015-03-03 08:59:20 -0800248 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
halcanary96fcdcc2015-08-27 07:41:13 -0700249 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
scroggo0eed6df2015-03-26 10:07:56 -0700250 sk_error_fn, sk_warning_fn);
scroggof24f2242015-03-03 08:59:20 -0800251 if (!png_ptr) {
scroggo3eada2a2015-04-01 09:33:23 -0700252 return false;
scroggof24f2242015-03-03 08:59:20 -0800253 }
254
255 AutoCleanPng autoClean(png_ptr);
256
257 png_infop info_ptr = png_create_info_struct(png_ptr);
halcanary96fcdcc2015-08-27 07:41:13 -0700258 if (info_ptr == nullptr) {
scroggo3eada2a2015-04-01 09:33:23 -0700259 return false;
scroggof24f2242015-03-03 08:59:20 -0800260 }
261
262 autoClean.setInfoPtr(info_ptr);
263
264 // FIXME: Could we use the return value of setjmp to specify the type of
265 // error?
266 if (setjmp(png_jmpbuf(png_ptr))) {
scroggo3eada2a2015-04-01 09:33:23 -0700267 return false;
scroggof24f2242015-03-03 08:59:20 -0800268 }
269
270 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);
271
scroggocf98fa92015-11-23 08:14:40 -0800272#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
msarett133eaaa2016-01-07 11:03:25 -0800273 // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
274 // This needs to be installed before we read the png header. Android may store ninepatch
275 // chunks in the header.
scroggocf98fa92015-11-23 08:14:40 -0800276 if (chunkReader) {
277 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
278 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
279 }
280#endif
scroggof24f2242015-03-03 08:59:20 -0800281
282 // The call to png_read_info() gives us all of the information from the
283 // PNG file before the first IDAT (image data chunk).
284 png_read_info(png_ptr, info_ptr);
285 png_uint_32 origWidth, origHeight;
286 int bitDepth, colorType;
287 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
288 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
289
scroggo6f29a3c2015-07-07 06:09:08 -0700290 if (bitDepthPtr) {
291 *bitDepthPtr = bitDepth;
292 }
293
scroggof24f2242015-03-03 08:59:20 -0800294 // sanity check for size
295 {
296 int64_t size = sk_64_mul(origWidth, origHeight);
297 // now check that if we are 4-bytes per pixel, we also don't overflow
298 if (size < 0 || size > (0x7FFFFFFF >> 2)) {
scroggo3eada2a2015-04-01 09:33:23 -0700299 return false;
scroggof24f2242015-03-03 08:59:20 -0800300 }
301 }
302
303 // Tell libpng to strip 16 bit/color files down to 8 bits/color
304 if (bitDepth == 16) {
305 png_set_strip_16(png_ptr);
306 }
307#ifdef PNG_READ_PACK_SUPPORTED
308 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
309 // byte into separate bytes (useful for paletted and grayscale images).
310 if (bitDepth < 8) {
311 png_set_packing(png_ptr);
312 }
313#endif
314 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
315 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
316 png_set_expand_gray_1_2_4_to_8(png_ptr);
317 }
318
scroggo6f29a3c2015-07-07 06:09:08 -0700319 // Now determine the default SkColorType and SkAlphaType and set required transforms
msarettf724b992015-10-15 06:41:06 -0700320 SkColorType skColorType = kUnknown_SkColorType;
321 SkAlphaType skAlphaType = kUnknown_SkAlphaType;
scroggof24f2242015-03-03 08:59:20 -0800322 switch (colorType) {
323 case PNG_COLOR_TYPE_PALETTE:
msarett438b2ad2015-04-09 12:43:10 -0700324 skColorType = kIndex_8_SkColorType;
emmaleer21cea722015-07-10 07:48:03 -0700325 skAlphaType = has_transparency_in_tRNS(png_ptr, info_ptr) ?
scroggof24f2242015-03-03 08:59:20 -0800326 kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
327 break;
scroggo6f29a3c2015-07-07 06:09:08 -0700328 case PNG_COLOR_TYPE_RGB:
emmaleer21cea722015-07-10 07:48:03 -0700329 if (has_transparency_in_tRNS(png_ptr, info_ptr)) {
scroggo6f29a3c2015-07-07 06:09:08 -0700330 //convert to RGBA with tranparency information in tRNS chunk if it exists
331 png_set_tRNS_to_alpha(png_ptr);
jvanverth6c90e092015-07-02 10:35:25 -0700332 skAlphaType = kUnpremul_SkAlphaType;
333 } else {
334 skAlphaType = kOpaque_SkAlphaType;
335 }
336 skColorType = kN32_SkColorType;
337 break;
scroggo6f29a3c2015-07-07 06:09:08 -0700338 case PNG_COLOR_TYPE_GRAY:
emmaleer21cea722015-07-10 07:48:03 -0700339 if (has_transparency_in_tRNS(png_ptr, info_ptr)) {
scroggo6f29a3c2015-07-07 06:09:08 -0700340 //FIXME: support gray with alpha as a color type
341 //convert to RGBA if there is transparentcy info in the tRNS chunk
342 png_set_tRNS_to_alpha(png_ptr);
343 png_set_gray_to_rgb(png_ptr);
344 skColorType = kN32_SkColorType;
345 skAlphaType = kUnpremul_SkAlphaType;
346 } else {
347 skColorType = kGray_8_SkColorType;
348 skAlphaType = kOpaque_SkAlphaType;
349 }
350 break;
351 case PNG_COLOR_TYPE_GRAY_ALPHA:
mtklein372d65c2016-01-27 13:01:41 -0800352 //FIXME: support gray with alpha as a color type
353 //convert to RGBA
jvanverth6c90e092015-07-02 10:35:25 -0700354 png_set_gray_to_rgb(png_ptr);
scroggo6f29a3c2015-07-07 06:09:08 -0700355 skColorType = kN32_SkColorType;
356 skAlphaType = kUnpremul_SkAlphaType;
357 break;
358 case PNG_COLOR_TYPE_RGBA:
359 skColorType = kN32_SkColorType;
360 skAlphaType = kUnpremul_SkAlphaType;
361 break;
362 default:
363 //all the color types have been covered above
364 SkASSERT(false);
scroggof24f2242015-03-03 08:59:20 -0800365 }
366
scroggo46c57472015-09-30 08:57:13 -0700367 int numberPasses = png_set_interlace_handling(png_ptr);
368 if (numberPassesPtr) {
369 *numberPassesPtr = numberPasses;
370 }
371
halcanary6950de62015-11-07 05:29:00 -0800372 // FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ).
scroggof24f2242015-03-03 08:59:20 -0800373
scroggo3eada2a2015-04-01 09:33:23 -0700374 if (imageInfo) {
scroggo6f29a3c2015-07-07 06:09:08 -0700375 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlphaType);
scroggo3eada2a2015-04-01 09:33:23 -0700376 }
scroggof24f2242015-03-03 08:59:20 -0800377 autoClean.detach();
scroggo3eada2a2015-04-01 09:33:23 -0700378 if (png_ptrp) {
379 *png_ptrp = png_ptr;
380 }
381 if (info_ptrp) {
382 *info_ptrp = info_ptr;
383 }
scroggo6f29a3c2015-07-07 06:09:08 -0700384
scroggo3eada2a2015-04-01 09:33:23 -0700385 return true;
386}
387
scroggocf98fa92015-11-23 08:14:40 -0800388SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkReader* chunkReader,
scroggo46c57472015-09-30 08:57:13 -0700389 png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses)
scroggof24f2242015-03-03 08:59:20 -0800390 : INHERITED(info, stream)
scroggocf98fa92015-11-23 08:14:40 -0800391 , fPngChunkReader(SkSafeRef(chunkReader))
scroggof24f2242015-03-03 08:59:20 -0800392 , fPng_ptr(png_ptr)
scroggo05245902015-03-25 11:11:52 -0700393 , fInfo_ptr(info_ptr)
394 , fSrcConfig(SkSwizzler::kUnknown)
scroggo46c57472015-09-30 08:57:13 -0700395 , fNumberPasses(numberPasses)
scroggo6f29a3c2015-07-07 06:09:08 -0700396 , fBitDepth(bitDepth)
msaretta4970dc2016-01-11 07:23:23 -0800397{}
scroggof24f2242015-03-03 08:59:20 -0800398
399SkPngCodec::~SkPngCodec() {
scroggo3eada2a2015-04-01 09:33:23 -0700400 this->destroyReadStruct();
401}
402
403void SkPngCodec::destroyReadStruct() {
404 if (fPng_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700405 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
scroggo3eada2a2015-04-01 09:33:23 -0700406 SkASSERT(fInfo_ptr);
407 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
halcanary96fcdcc2015-08-27 07:41:13 -0700408 fPng_ptr = nullptr;
409 fInfo_ptr = nullptr;
scroggo3eada2a2015-04-01 09:33:23 -0700410 }
scroggof24f2242015-03-03 08:59:20 -0800411}
412
413///////////////////////////////////////////////////////////////////////////////
414// Getting the pixels
415///////////////////////////////////////////////////////////////////////////////
416
scroggo05245902015-03-25 11:11:52 -0700417SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
msarett438b2ad2015-04-09 12:43:10 -0700418 const Options& options,
msarett9e43cab2015-04-29 07:38:43 -0700419 SkPMColor ctable[],
msarett438b2ad2015-04-09 12:43:10 -0700420 int* ctableCount) {
scroggof24f2242015-03-03 08:59:20 -0800421 // FIXME: Could we use the return value of setjmp to specify the type of
422 // error?
423 if (setjmp(png_jmpbuf(fPng_ptr))) {
scroggo230d4ac2015-03-26 07:15:55 -0700424 SkCodecPrintf("setjmp long jump!\n");
scroggof24f2242015-03-03 08:59:20 -0800425 return kInvalidInput;
426 }
mtklein372d65c2016-01-27 13:01:41 -0800427 png_read_update_info(fPng_ptr, fInfo_ptr);
scroggof24f2242015-03-03 08:59:20 -0800428
scroggo46c57472015-09-30 08:57:13 -0700429 //srcColorType was determined in read_header() which determined png color type
scroggo6f29a3c2015-07-07 06:09:08 -0700430 const SkColorType srcColorType = this->getInfo().colorType();
431
432 switch (srcColorType) {
433 case kIndex_8_SkColorType:
434 //decode palette to Skia format
435 fSrcConfig = SkSwizzler::kIndex;
scroggo9b2cdbf2015-07-10 12:07:02 -0700436 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(),
scroggo6f29a3c2015-07-07 06:09:08 -0700437 ctableCount)) {
438 return kInvalidInput;
439 }
440 break;
441 case kGray_8_SkColorType:
442 fSrcConfig = SkSwizzler::kGray;
mtklein372d65c2016-01-27 13:01:41 -0800443 break;
scroggo6f29a3c2015-07-07 06:09:08 -0700444 case kN32_SkColorType:
445 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
msarettbda86092016-01-19 10:40:12 -0800446 fSrcConfig = SkSwizzler::kRGB;
scroggo6f29a3c2015-07-07 06:09:08 -0700447 } else {
448 fSrcConfig = SkSwizzler::kRGBA;
449 }
450 break;
451 default:
452 //would have exited before now if the colorType was supported by png
453 SkASSERT(false);
mtklein372d65c2016-01-27 13:01:41 -0800454 }
msarett9e43cab2015-04-29 07:38:43 -0700455
456 // Copy the color table to the client if they request kIndex8 mode
457 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
458
459 // Create the swizzler. SkPngCodec retains ownership of the color table.
msarett99f567e2015-08-05 12:58:26 -0700460 const SkPMColor* colors = get_color_ptr(fColorTable.get());
msarettfdb47572015-10-13 12:50:14 -0700461 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, options));
scroggo05245902015-03-25 11:11:52 -0700462 if (!fSwizzler) {
scroggof24f2242015-03-03 08:59:20 -0800463 // FIXME: CreateSwizzler could fail for another reason.
464 return kUnimplemented;
465 }
scroggo05245902015-03-25 11:11:52 -0700466 return kSuccess;
467}
468
scroggo6f29a3c2015-07-07 06:09:08 -0700469
scroggob427db12015-08-12 07:24:13 -0700470bool SkPngCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -0700471 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
scroggob427db12015-08-12 07:24:13 -0700472 // succeeds, they will be repopulated, and if it fails, they will
halcanary96fcdcc2015-08-27 07:41:13 -0700473 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
scroggob427db12015-08-12 07:24:13 -0700474 // come through this function which will rewind and again attempt
475 // to reinitialize them.
476 this->destroyReadStruct();
477
478 png_structp png_ptr;
479 png_infop info_ptr;
scroggocf98fa92015-11-23 08:14:40 -0800480 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr,
481 nullptr, nullptr, nullptr)) {
scroggob427db12015-08-12 07:24:13 -0700482 return false;
scroggo58421542015-04-01 11:25:20 -0700483 }
scroggob427db12015-08-12 07:24:13 -0700484
485 fPng_ptr = png_ptr;
486 fInfo_ptr = info_ptr;
487 return true;
scroggo58421542015-04-01 11:25:20 -0700488}
489
scroggo05245902015-03-25 11:11:52 -0700490SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
msarett614aa072015-07-27 15:13:17 -0700491 size_t dstRowBytes, const Options& options,
msarette6dd0042015-10-09 11:07:34 -0700492 SkPMColor ctable[], int* ctableCount,
493 int* rowsDecoded) {
scroggo6f29a3c2015-07-07 06:09:08 -0700494 if (!conversion_possible(requestedInfo, this->getInfo())) {
495 return kInvalidConversion;
496 }
scroggob636b452015-07-22 07:16:20 -0700497 if (options.fSubset) {
498 // Subsets are not supported.
499 return kUnimplemented;
500 }
scroggo05245902015-03-25 11:11:52 -0700501
msarett9e43cab2015-04-29 07:38:43 -0700502 // Note that ctable and ctableCount may be modified if there is a color table
msarettfdb47572015-10-13 12:50:14 -0700503 const Result result = this->initializeSwizzler(requestedInfo, options, ctable, ctableCount);
scroggo05245902015-03-25 11:11:52 -0700504 if (result != kSuccess) {
505 return result;
506 }
scroggo05245902015-03-25 11:11:52 -0700507 // FIXME: Could we use the return value of setjmp to specify the type of
508 // error?
msarette6dd0042015-10-09 11:07:34 -0700509 int row = 0;
510 // This must be declared above the call to setjmp to avoid memory leaks on incomplete images.
scroggo565901d2015-12-10 10:44:13 -0800511 SkAutoTMalloc<uint8_t> storage;
scroggo05245902015-03-25 11:11:52 -0700512 if (setjmp(png_jmpbuf(fPng_ptr))) {
msarette6dd0042015-10-09 11:07:34 -0700513 // Assume that any error that occurs while reading rows is caused by an incomplete input.
514 if (fNumberPasses > 1) {
515 // FIXME (msarett): Handle incomplete interlaced pngs.
516 return kInvalidInput;
517 }
518 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium,
519 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192
520 // bytes), and if we can't fill the buffer, we immediately fail.
521 // For example, if we try to read 8192 bytes, and the image (incorrectly) only contains
522 // half that, which may have been enough to contain a non-zero number of lines, we fail
523 // when we could have decoded a few more lines and then failed.
524 // The read function that we provide for libpng has no way of indicating that we have
525 // made a partial read.
526 // Making our buffer size smaller improves our incomplete decodes, but what impact does
527 // it have on regular decode performance? Should we investigate using a different API
528 // instead of png_read_row(s)? Chromium uses png_process_data.
529 *rowsDecoded = row;
530 return kIncompleteInput;
scroggo05245902015-03-25 11:11:52 -0700531 }
532
scroggo46c57472015-09-30 08:57:13 -0700533 // FIXME: We could split these out based on subclass.
msarett614aa072015-07-27 15:13:17 -0700534 void* dstRow = dst;
scroggo05245902015-03-25 11:11:52 -0700535 if (fNumberPasses > 1) {
scroggof24f2242015-03-03 08:59:20 -0800536 const int width = requestedInfo.width();
537 const int height = requestedInfo.height();
scroggo05245902015-03-25 11:11:52 -0700538 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
msarett614aa072015-07-27 15:13:17 -0700539 const size_t srcRowBytes = width * bpp;
scroggof24f2242015-03-03 08:59:20 -0800540
541 storage.reset(width * height * bpp);
scroggo565901d2015-12-10 10:44:13 -0800542 uint8_t* const base = storage.get();
scroggof24f2242015-03-03 08:59:20 -0800543
scroggo05245902015-03-25 11:11:52 -0700544 for (int i = 0; i < fNumberPasses; i++) {
msarett614aa072015-07-27 15:13:17 -0700545 uint8_t* srcRow = base;
scroggof24f2242015-03-03 08:59:20 -0800546 for (int y = 0; y < height; y++) {
msarett614aa072015-07-27 15:13:17 -0700547 uint8_t* bmRow = srcRow;
scroggof24f2242015-03-03 08:59:20 -0800548 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1);
msarett614aa072015-07-27 15:13:17 -0700549 srcRow += srcRowBytes;
scroggof24f2242015-03-03 08:59:20 -0800550 }
551 }
552
553 // Now swizzle it.
msarett614aa072015-07-27 15:13:17 -0700554 uint8_t* srcRow = base;
scroggof24f2242015-03-03 08:59:20 -0800555 for (int y = 0; y < height; y++) {
msaretta4970dc2016-01-11 07:23:23 -0800556 fSwizzler->swizzle(dstRow, srcRow);
msarett614aa072015-07-27 15:13:17 -0700557 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
558 srcRow += srcRowBytes;
scroggof24f2242015-03-03 08:59:20 -0800559 }
560 } else {
scroggo05245902015-03-25 11:11:52 -0700561 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConfig));
scroggo565901d2015-12-10 10:44:13 -0800562 uint8_t* srcRow = storage.get();
msarette6dd0042015-10-09 11:07:34 -0700563 for (; row < requestedInfo.height(); row++) {
scroggof24f2242015-03-03 08:59:20 -0800564 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
scroggo46c57472015-09-30 08:57:13 -0700565 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetScanlines.
msaretta4970dc2016-01-11 07:23:23 -0800566 fSwizzler->swizzle(dstRow, srcRow);
msarett614aa072015-07-27 15:13:17 -0700567 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
scroggof24f2242015-03-03 08:59:20 -0800568 }
569 }
570
scroggo05245902015-03-25 11:11:52 -0700571 // FIXME: do we need substituteTranspColor? Note that we cannot do it for
572 // scanline decoding, but we could do it here. Alternatively, we could do
573 // it as we go, instead of in post-processing like SkPNGImageDecoder.
scroggof24f2242015-03-03 08:59:20 -0800574
scroggo05245902015-03-25 11:11:52 -0700575 if (setjmp(png_jmpbuf(fPng_ptr))) {
576 // We've already read all the scanlines. This is a success.
emmaleer973ae862015-07-20 13:38:44 -0700577 return kSuccess;
scroggo05245902015-03-25 11:11:52 -0700578 }
emmaleer973ae862015-07-20 13:38:44 -0700579
580 // read rest of file, and get additional comment and time chunks in info_ptr
scroggo05245902015-03-25 11:11:52 -0700581 png_read_end(fPng_ptr, fInfo_ptr);
scroggo46c57472015-09-30 08:57:13 -0700582
emmaleer973ae862015-07-20 13:38:44 -0700583 return kSuccess;
scroggo05245902015-03-25 11:11:52 -0700584}
585
msarette6dd0042015-10-09 11:07:34 -0700586uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType) const {
587 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
588 if (colorPtr) {
589 return get_color_table_fill_value(colorType, colorPtr, 0);
590 }
591 return INHERITED::onGetFillValue(colorType, alphaType);
592}
593
scroggo46c57472015-09-30 08:57:13 -0700594// Subclass of SkPngCodec which supports scanline decoding
595class SkPngScanlineDecoder : public SkPngCodec {
scroggo05245902015-03-25 11:11:52 -0700596public:
scroggo46c57472015-09-30 08:57:13 -0700597 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
scroggocf98fa92015-11-23 08:14:40 -0800598 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
599 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1)
msarettf724b992015-10-15 06:41:06 -0700600 , fSrcRow(nullptr)
scroggo1c005e42015-08-04 09:24:45 -0700601 {}
602
scroggo46c57472015-09-30 08:57:13 -0700603 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
604 SkPMColor ctable[], int* ctableCount) override {
scroggo1c005e42015-08-04 09:24:45 -0700605 if (!conversion_possible(dstInfo, this->getInfo())) {
scroggo46c57472015-09-30 08:57:13 -0700606 return kInvalidConversion;
scroggo1c005e42015-08-04 09:24:45 -0700607 }
608
scroggo46c57472015-09-30 08:57:13 -0700609 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
610 ctableCount);
611 if (result != kSuccess) {
scroggo1c005e42015-08-04 09:24:45 -0700612 return result;
613 }
614
scroggo46c57472015-09-30 08:57:13 -0700615 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig()));
scroggo565901d2015-12-10 10:44:13 -0800616 fSrcRow = fStorage.get();
scroggo1c005e42015-08-04 09:24:45 -0700617
scroggo46c57472015-09-30 08:57:13 -0700618 return kSuccess;
scroggo05245902015-03-25 11:11:52 -0700619 }
620
msarette6dd0042015-10-09 11:07:34 -0700621 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
622 // Assume that an error in libpng indicates an incomplete input.
623 int row = 0;
scroggo46c57472015-09-30 08:57:13 -0700624 if (setjmp(png_jmpbuf(this->png_ptr()))) {
scroggo230d4ac2015-03-26 07:15:55 -0700625 SkCodecPrintf("setjmp long jump!\n");
msarette6dd0042015-10-09 11:07:34 -0700626 return row;
scroggo05245902015-03-25 11:11:52 -0700627 }
628
msarett614aa072015-07-27 15:13:17 -0700629 void* dstRow = dst;
msarette6dd0042015-10-09 11:07:34 -0700630 for (; row < count; row++) {
scroggo46c57472015-09-30 08:57:13 -0700631 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
msaretta4970dc2016-01-11 07:23:23 -0800632 this->swizzler()->swizzle(dstRow, fSrcRow);
msarett614aa072015-07-27 15:13:17 -0700633 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
scroggo05245902015-03-25 11:11:52 -0700634 }
scroggo46c57472015-09-30 08:57:13 -0700635
msarette6dd0042015-10-09 11:07:34 -0700636 return row;
scroggo05245902015-03-25 11:11:52 -0700637 }
638
msarette6dd0042015-10-09 11:07:34 -0700639 bool onSkipScanlines(int count) override {
640 // Assume that an error in libpng indicates an incomplete input.
scroggo46c57472015-09-30 08:57:13 -0700641 if (setjmp(png_jmpbuf(this->png_ptr()))) {
scroggo230d4ac2015-03-26 07:15:55 -0700642 SkCodecPrintf("setjmp long jump!\n");
msarette6dd0042015-10-09 11:07:34 -0700643 return false;
scroggo05245902015-03-25 11:11:52 -0700644 }
mtklein372d65c2016-01-27 13:01:41 -0800645 //there is a potential tradeoff of memory vs speed created by putting this in a loop.
646 //calling png_read_rows in a loop is insignificantly slower than calling it once with count
emmaleer7dc91902015-05-27 08:49:04 -0700647 //as png_read_rows has it's own loop which calls png_read_row count times.
msarette6dd0042015-10-09 11:07:34 -0700648 for (int row = 0; row < count; row++) {
scroggo46c57472015-09-30 08:57:13 -0700649 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
emmaleer7dc91902015-05-27 08:49:04 -0700650 }
msarette6dd0042015-10-09 11:07:34 -0700651 return true;
scroggo05245902015-03-25 11:11:52 -0700652 }
653
scroggo05245902015-03-25 11:11:52 -0700654private:
scroggo565901d2015-12-10 10:44:13 -0800655 SkAutoTMalloc<uint8_t> fStorage;
scroggo9b2cdbf2015-07-10 12:07:02 -0700656 uint8_t* fSrcRow;
scroggo05245902015-03-25 11:11:52 -0700657
scroggo46c57472015-09-30 08:57:13 -0700658 typedef SkPngCodec INHERITED;
scroggo05245902015-03-25 11:11:52 -0700659};
660
emmaleer0a4c3cb2015-06-22 10:40:21 -0700661
scroggo46c57472015-09-30 08:57:13 -0700662class SkPngInterlacedScanlineDecoder : public SkPngCodec {
emmaleer0a4c3cb2015-06-22 10:40:21 -0700663public:
scroggo46c57472015-09-30 08:57:13 -0700664 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
scroggocf98fa92015-11-23 08:14:40 -0800665 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr,
666 int bitDepth, int numberPasses)
667 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses)
scroggo46c57472015-09-30 08:57:13 -0700668 , fHeight(-1)
scroggo1c005e42015-08-04 09:24:45 -0700669 , fCanSkipRewind(false)
scroggo1c005e42015-08-04 09:24:45 -0700670 {
scroggo46c57472015-09-30 08:57:13 -0700671 SkASSERT(numberPasses != 1);
672 }
673
674 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
msarettfdb47572015-10-13 12:50:14 -0700675 SkPMColor ctable[], int* ctableCount) override {
scroggo1c005e42015-08-04 09:24:45 -0700676 if (!conversion_possible(dstInfo, this->getInfo())) {
mtklein372d65c2016-01-27 13:01:41 -0800677 return kInvalidConversion;
scroggo1c005e42015-08-04 09:24:45 -0700678 }
679
msarettfdb47572015-10-13 12:50:14 -0700680 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
681 ctableCount);
682 if (result != kSuccess) {
scroggo1c005e42015-08-04 09:24:45 -0700683 return result;
684 }
685
scroggo1c005e42015-08-04 09:24:45 -0700686 fHeight = dstInfo.height();
scroggo46c57472015-09-30 08:57:13 -0700687 // FIXME: This need not be called on a second call to onStartScanlineDecode.
688 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig());
scroggo1c005e42015-08-04 09:24:45 -0700689 fGarbageRow.reset(fSrcRowBytes);
690 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
691 fCanSkipRewind = true;
692
693 return SkCodec::kSuccess;
694 }
695
msarette6dd0042015-10-09 11:07:34 -0700696 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
scroggo1c005e42015-08-04 09:24:45 -0700697 // rewind stream if have previously called onGetScanlines,
698 // since we need entire progressive image to get scanlines
699 if (fCanSkipRewind) {
scroggo46c57472015-09-30 08:57:13 -0700700 // We already rewound in onStartScanlineDecode, so there is no reason to rewind.
scroggo1c005e42015-08-04 09:24:45 -0700701 // Next time onGetScanlines is called, we will need to rewind.
702 fCanSkipRewind = false;
scroggo46c57472015-09-30 08:57:13 -0700703 } else {
704 // rewindIfNeeded resets fCurrScanline, since it assumes that start
705 // needs to be called again before scanline decoding. PNG scanline
706 // decoding is the exception, since it needs to rewind between
707 // calls to getScanlines. Keep track of fCurrScanline, to undo the
708 // reset.
msarette6dd0042015-10-09 11:07:34 -0700709 const int currScanline = this->nextScanline();
scroggo46c57472015-09-30 08:57:13 -0700710 // This method would never be called if currScanline is -1
711 SkASSERT(currScanline != -1);
712
713 if (!this->rewindIfNeeded()) {
714 return kCouldNotRewind;
715 }
msarettcb0d5c92015-12-03 12:23:43 -0800716 this->updateCurrScanline(currScanline);
scroggo1c005e42015-08-04 09:24:45 -0700717 }
718
scroggo46c57472015-09-30 08:57:13 -0700719 if (setjmp(png_jmpbuf(this->png_ptr()))) {
emmaleer0a4c3cb2015-06-22 10:40:21 -0700720 SkCodecPrintf("setjmp long jump!\n");
msarette6dd0042015-10-09 11:07:34 -0700721 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
722 // we may be able to report that all of the memory has been initialized. Even if we
723 // fail on the first pass, we can still report than some scanlines are initialized.
724 return 0;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700725 }
scroggo565901d2015-12-10 10:44:13 -0800726 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
727 uint8_t* storagePtr = storage.get();
emmaleer0a4c3cb2015-06-22 10:40:21 -0700728 uint8_t* srcRow;
msarette6dd0042015-10-09 11:07:34 -0700729 const int startRow = this->nextScanline();
scroggo46c57472015-09-30 08:57:13 -0700730 for (int i = 0; i < this->numberPasses(); i++) {
731 // read rows we planned to skip into garbage row
732 for (int y = 0; y < startRow; y++){
733 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700734 }
scroggo46c57472015-09-30 08:57:13 -0700735 // read rows we care about into buffer
emmaleer0a4c3cb2015-06-22 10:40:21 -0700736 srcRow = storagePtr;
737 for (int y = 0; y < count; y++) {
scroggo46c57472015-09-30 08:57:13 -0700738 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700739 srcRow += fSrcRowBytes;
740 }
scroggo46c57472015-09-30 08:57:13 -0700741 // read rows we don't want into garbage buffer
742 for (int y = 0; y < fHeight - startRow - count; y++) {
743 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700744 }
745 }
746 //swizzle the rows we care about
747 srcRow = storagePtr;
msarett614aa072015-07-27 15:13:17 -0700748 void* dstRow = dst;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700749 for (int y = 0; y < count; y++) {
msaretta4970dc2016-01-11 07:23:23 -0800750 this->swizzler()->swizzle(dstRow, srcRow);
msarett614aa072015-07-27 15:13:17 -0700751 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700752 srcRow += fSrcRowBytes;
753 }
scroggo46c57472015-09-30 08:57:13 -0700754
msarette6dd0042015-10-09 11:07:34 -0700755 return count;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700756 }
757
msarette6dd0042015-10-09 11:07:34 -0700758 bool onSkipScanlines(int count) override {
scroggo46c57472015-09-30 08:57:13 -0700759 // The non-virtual version will update fCurrScanline.
msarette6dd0042015-10-09 11:07:34 -0700760 return true;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700761 }
762
msarett5406d6f2015-08-31 06:55:13 -0700763 SkScanlineOrder onGetScanlineOrder() const override {
764 return kNone_SkScanlineOrder;
emmaleer8f4ba762015-08-14 07:44:46 -0700765 }
766
emmaleer0a4c3cb2015-06-22 10:40:21 -0700767private:
scroggo9b2cdbf2015-07-10 12:07:02 -0700768 int fHeight;
769 size_t fSrcRowBytes;
770 SkAutoMalloc fGarbageRow;
771 uint8_t* fGarbageRowPtr;
scroggo1c005e42015-08-04 09:24:45 -0700772 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
773 // is called whenever some action is taken that reads the stream and
774 // therefore the next call will require a rewind. So it modifies a boolean
775 // to note that the *next* time it is called a rewind is needed.
scroggo46c57472015-09-30 08:57:13 -0700776 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
777 // onStartScanlineDecode followed by onGetScanlines does *not* require a
778 // rewind. Since rewindIfNeeded does not have this flexibility, we need to
779 // add another layer.
scroggo1c005e42015-08-04 09:24:45 -0700780 bool fCanSkipRewind;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700781
scroggo46c57472015-09-30 08:57:13 -0700782 typedef SkPngCodec INHERITED;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700783};
784
scroggocf98fa92015-11-23 08:14:40 -0800785SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
scroggo46c57472015-09-30 08:57:13 -0700786 SkAutoTDelete<SkStream> streamDeleter(stream);
787 png_structp png_ptr;
788 png_infop info_ptr;
789 SkImageInfo imageInfo;
790 int bitDepth;
791 int numberPasses;
792
scroggocf98fa92015-11-23 08:14:40 -0800793 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitDepth,
794 &numberPasses)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700795 return nullptr;
scroggo05245902015-03-25 11:11:52 -0700796 }
797
scroggo46c57472015-09-30 08:57:13 -0700798 if (1 == numberPasses) {
scroggocf98fa92015-11-23 08:14:40 -0800799 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
800 png_ptr, info_ptr, bitDepth);
scroggo05245902015-03-25 11:11:52 -0700801 }
802
scroggocf98fa92015-11-23 08:14:40 -0800803 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
804 png_ptr, info_ptr, bitDepth, numberPasses);
scroggo05245902015-03-25 11:11:52 -0700805}