blob: 155cbacf4db0997bd9a4fcd94ad0b95013b3d220 [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
mtklein62358e72016-01-27 18:26:31 -080020// png_struct::read_filter[] was added in libpng 1.5.7.
21#if defined(__SSE2__) && PNG_LIBPNG_VER >= 10507
mtklein372d65c2016-01-27 13:01:41 -080022 #include "pngstruct.h"
23
24 extern "C" void sk_png_init_filter_functions_sse2(png_structp png, unsigned int bpp) {
25 if (bpp == 3) {
26 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub3_sse2;
27 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg3_sse2;
28 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth3_sse2;
29 }
30 if (bpp == 4) {
31 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub4_sse2;
32 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg4_sse2;
33 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth4_sse2;
34 }
35 }
36#endif
37
scroggof24f2242015-03-03 08:59:20 -080038///////////////////////////////////////////////////////////////////////////////
39// Helper macros
40///////////////////////////////////////////////////////////////////////////////
41
42#ifndef png_jmpbuf
43# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
44#endif
45
46/* These were dropped in libpng >= 1.4 */
47#ifndef png_infopp_NULL
halcanary96fcdcc2015-08-27 07:41:13 -070048 #define png_infopp_NULL nullptr
scroggof24f2242015-03-03 08:59:20 -080049#endif
50
51#ifndef png_bytepp_NULL
halcanary96fcdcc2015-08-27 07:41:13 -070052 #define png_bytepp_NULL nullptr
scroggof24f2242015-03-03 08:59:20 -080053#endif
54
55#ifndef int_p_NULL
halcanary96fcdcc2015-08-27 07:41:13 -070056 #define int_p_NULL nullptr
scroggof24f2242015-03-03 08:59:20 -080057#endif
58
59#ifndef png_flush_ptr_NULL
halcanary96fcdcc2015-08-27 07:41:13 -070060 #define png_flush_ptr_NULL nullptr
scroggof24f2242015-03-03 08:59:20 -080061#endif
62
63///////////////////////////////////////////////////////////////////////////////
64// Callback functions
65///////////////////////////////////////////////////////////////////////////////
66
67static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
scroggo230d4ac2015-03-26 07:15:55 -070068 SkCodecPrintf("------ png error %s\n", msg);
scroggof24f2242015-03-03 08:59:20 -080069 longjmp(png_jmpbuf(png_ptr), 1);
70}
71
scroggo0eed6df2015-03-26 10:07:56 -070072void sk_warning_fn(png_structp, png_const_charp msg) {
73 SkCodecPrintf("----- png warning %s\n", msg);
74}
75
scroggof24f2242015-03-03 08:59:20 -080076static void sk_read_fn(png_structp png_ptr, png_bytep data,
77 png_size_t length) {
78 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr));
79 const size_t bytes = stream->read(data, length);
80 if (bytes != length) {
81 // FIXME: We want to report the fact that the stream was truncated.
82 // One way to do that might be to pass a enum to longjmp so setjmp can
83 // specify the failure.
84 png_error(png_ptr, "Read Error!");
85 }
86}
87
scroggocf98fa92015-11-23 08:14:40 -080088#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
89static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
90 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
91 // readChunk() returning true means continue decoding
92 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1;
93}
94#endif
95
scroggof24f2242015-03-03 08:59:20 -080096///////////////////////////////////////////////////////////////////////////////
97// Helpers
98///////////////////////////////////////////////////////////////////////////////
99
100class AutoCleanPng : public SkNoncopyable {
101public:
102 AutoCleanPng(png_structp png_ptr)
103 : fPng_ptr(png_ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700104 , fInfo_ptr(nullptr) {}
scroggof24f2242015-03-03 08:59:20 -0800105
106 ~AutoCleanPng() {
halcanary96fcdcc2015-08-27 07:41:13 -0700107 // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
scroggof24f2242015-03-03 08:59:20 -0800108 if (fPng_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700109 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
scroggof24f2242015-03-03 08:59:20 -0800110 png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL);
111 }
112 }
113
114 void setInfoPtr(png_infop info_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700115 SkASSERT(nullptr == fInfo_ptr);
scroggof24f2242015-03-03 08:59:20 -0800116 fInfo_ptr = info_ptr;
117 }
118
119 void detach() {
halcanary96fcdcc2015-08-27 07:41:13 -0700120 fPng_ptr = nullptr;
121 fInfo_ptr = nullptr;
scroggof24f2242015-03-03 08:59:20 -0800122 }
123
124private:
125 png_structp fPng_ptr;
126 png_infop fInfo_ptr;
127};
128#define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
129
emmaleer21cea722015-07-10 07:48:03 -0700130//checks if there is transparency info in the tRNS chunk
131//image types which could have data in the tRNS chunk include: Index8, Gray8, RGB
132static bool has_transparency_in_tRNS(png_structp png_ptr,
scroggof24f2242015-03-03 08:59:20 -0800133 png_infop info_ptr) {
134 if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
135 return false;
136 }
137
138 png_bytep trans;
139 int num_trans;
halcanary96fcdcc2015-08-27 07:41:13 -0700140 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr);
scroggof24f2242015-03-03 08:59:20 -0800141 return num_trans > 0;
142}
143
144// Method for coverting to either an SkPMColor or a similarly packed
145// unpremultiplied color.
146typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
147
148// Note: SkColorTable claims to store SkPMColors, which is not necessarily
149// the case here.
scroggo9b2cdbf42015-07-10 12:07:02 -0700150bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) {
scroggof24f2242015-03-03 08:59:20 -0800151 int numPalette;
152 png_colorp palette;
153 png_bytep trans;
154
scroggo05245902015-03-25 11:11:52 -0700155 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) {
156 return false;
scroggof24f2242015-03-03 08:59:20 -0800157 }
158
msarett438b2ad2015-04-09 12:43:10 -0700159 // Note: These are not necessarily SkPMColors
scroggof24f2242015-03-03 08:59:20 -0800160 SkPMColor colorStorage[256]; // worst-case storage
161 SkPMColor* colorPtr = colorStorage;
162
163 int numTrans;
scroggo05245902015-03-25 11:11:52 -0700164 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700165 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, nullptr);
scroggof24f2242015-03-03 08:59:20 -0800166 } else {
167 numTrans = 0;
168 }
169
170 // check for bad images that might make us crash
171 if (numTrans > numPalette) {
172 numTrans = numPalette;
173 }
174
175 int index = 0;
scroggof24f2242015-03-03 08:59:20 -0800176
177 // Choose which function to use to create the color table. If the final destination's
178 // colortype is unpremultiplied, the color table will store unpremultiplied colors.
179 PackColorProc proc;
180 if (premultiply) {
181 proc = &SkPreMultiplyARGB;
182 } else {
183 proc = &SkPackARGB32NoCheck;
184 }
185 for (; index < numTrans; index++) {
scroggof24f2242015-03-03 08:59:20 -0800186 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
187 palette++;
188 }
189
scroggof24f2242015-03-03 08:59:20 -0800190 for (; index < numPalette; index++) {
191 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
192 palette++;
193 }
194
msarett438b2ad2015-04-09 12:43:10 -0700195 /* BUGGY IMAGE WORKAROUND
196 Invalid images could contain pixel values that are greater than the number of palette
197 entries. Since we use pixel values as indices into the palette this could result in reading
198 beyond the end of the palette which could leak the contents of uninitialized memory. To
199 ensure this doesn't happen, we grow the colortable to the maximum size that can be
200 addressed by the bitdepth of the image and fill it with the last palette color or black if
201 the palette is empty (really broken image).
202 */
scroggo9b2cdbf42015-07-10 12:07:02 -0700203 int colorCount = SkTMax(numPalette, 1 << SkTMin(fBitDepth, 8));
msarett438b2ad2015-04-09 12:43:10 -0700204 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0);
205 for (; index < colorCount; index++) {
206 *colorPtr++ = lastColor;
207 }
208
209 // Set the new color count
halcanary96fcdcc2015-08-27 07:41:13 -0700210 if (ctableCount != nullptr) {
msarett438b2ad2015-04-09 12:43:10 -0700211 *ctableCount = colorCount;
scroggof24f2242015-03-03 08:59:20 -0800212 }
213
halcanary385fe4d2015-08-26 13:07:48 -0700214 fColorTable.reset(new SkColorTable(colorStorage, colorCount));
scroggo05245902015-03-25 11:11:52 -0700215 return true;
scroggof24f2242015-03-03 08:59:20 -0800216}
217
218///////////////////////////////////////////////////////////////////////////////
219// Creation
220///////////////////////////////////////////////////////////////////////////////
221
scroggodb30be22015-12-08 18:54:13 -0800222bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
223 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
scroggof24f2242015-03-03 08:59:20 -0800224}
225
scroggocf98fa92015-11-23 08:14:40 -0800226// Reads the header and initializes the output fields, if not NULL.
227//
228// @param stream Input data. Will be read to get enough information to properly
229// setup the codec.
230// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
231// If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
232// expected to continue to own it for the lifetime of the png_ptr.
233// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
234// png_structp on success.
235// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
236// png_infop on success;
237// @param imageInfo Optional output variable. If non-NULL, will be set to
238// reflect the properties of the encoded image on success.
239// @param bitDepthPtr Optional output variable. If non-NULL, will be set to the
240// bit depth of the encoded image on success.
241// @param numberPassesPtr Optional output variable. If non-NULL, will be set to
242// the number_passes of the encoded image on success.
243// @return true on success, in which case the caller is responsible for calling
244// png_destroy_read_struct(png_ptrp, info_ptrp).
245// If it returns false, the passed in fields (except stream) are unchanged.
246static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
247 png_structp* png_ptrp, png_infop* info_ptrp,
248 SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPassesPtr) {
scroggof24f2242015-03-03 08:59:20 -0800249 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
halcanary96fcdcc2015-08-27 07:41:13 -0700250 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
scroggo0eed6df2015-03-26 10:07:56 -0700251 sk_error_fn, sk_warning_fn);
scroggof24f2242015-03-03 08:59:20 -0800252 if (!png_ptr) {
scroggo3eada2a2015-04-01 09:33:23 -0700253 return false;
scroggof24f2242015-03-03 08:59:20 -0800254 }
255
256 AutoCleanPng autoClean(png_ptr);
257
258 png_infop info_ptr = png_create_info_struct(png_ptr);
halcanary96fcdcc2015-08-27 07:41:13 -0700259 if (info_ptr == nullptr) {
scroggo3eada2a2015-04-01 09:33:23 -0700260 return false;
scroggof24f2242015-03-03 08:59:20 -0800261 }
262
263 autoClean.setInfoPtr(info_ptr);
264
265 // FIXME: Could we use the return value of setjmp to specify the type of
266 // error?
267 if (setjmp(png_jmpbuf(png_ptr))) {
scroggo3eada2a2015-04-01 09:33:23 -0700268 return false;
scroggof24f2242015-03-03 08:59:20 -0800269 }
270
271 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);
272
scroggocf98fa92015-11-23 08:14:40 -0800273#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
msarett133eaaa2016-01-07 11:03:25 -0800274 // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
275 // This needs to be installed before we read the png header. Android may store ninepatch
276 // chunks in the header.
scroggocf98fa92015-11-23 08:14:40 -0800277 if (chunkReader) {
278 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
279 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
280 }
281#endif
scroggof24f2242015-03-03 08:59:20 -0800282
283 // The call to png_read_info() gives us all of the information from the
284 // PNG file before the first IDAT (image data chunk).
285 png_read_info(png_ptr, info_ptr);
286 png_uint_32 origWidth, origHeight;
287 int bitDepth, colorType;
288 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
289 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
290
scroggo6f29a3c2015-07-07 06:09:08 -0700291 if (bitDepthPtr) {
292 *bitDepthPtr = bitDepth;
293 }
294
scroggof24f2242015-03-03 08:59:20 -0800295 // sanity check for size
296 {
297 int64_t size = sk_64_mul(origWidth, origHeight);
298 // now check that if we are 4-bytes per pixel, we also don't overflow
299 if (size < 0 || size > (0x7FFFFFFF >> 2)) {
scroggo3eada2a2015-04-01 09:33:23 -0700300 return false;
scroggof24f2242015-03-03 08:59:20 -0800301 }
302 }
303
304 // Tell libpng to strip 16 bit/color files down to 8 bits/color
305 if (bitDepth == 16) {
306 png_set_strip_16(png_ptr);
307 }
308#ifdef PNG_READ_PACK_SUPPORTED
309 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
310 // byte into separate bytes (useful for paletted and grayscale images).
311 if (bitDepth < 8) {
312 png_set_packing(png_ptr);
313 }
314#endif
315 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
316 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
317 png_set_expand_gray_1_2_4_to_8(png_ptr);
318 }
319
scroggo6f29a3c2015-07-07 06:09:08 -0700320 // Now determine the default SkColorType and SkAlphaType and set required transforms
msarettf724b992015-10-15 06:41:06 -0700321 SkColorType skColorType = kUnknown_SkColorType;
322 SkAlphaType skAlphaType = kUnknown_SkAlphaType;
scroggof24f2242015-03-03 08:59:20 -0800323 switch (colorType) {
324 case PNG_COLOR_TYPE_PALETTE:
msarett438b2ad2015-04-09 12:43:10 -0700325 skColorType = kIndex_8_SkColorType;
emmaleer21cea722015-07-10 07:48:03 -0700326 skAlphaType = has_transparency_in_tRNS(png_ptr, info_ptr) ?
scroggof24f2242015-03-03 08:59:20 -0800327 kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
328 break;
scroggo6f29a3c2015-07-07 06:09:08 -0700329 case PNG_COLOR_TYPE_RGB:
emmaleer21cea722015-07-10 07:48:03 -0700330 if (has_transparency_in_tRNS(png_ptr, info_ptr)) {
scroggo6f29a3c2015-07-07 06:09:08 -0700331 //convert to RGBA with tranparency information in tRNS chunk if it exists
332 png_set_tRNS_to_alpha(png_ptr);
jvanverth6c90e092015-07-02 10:35:25 -0700333 skAlphaType = kUnpremul_SkAlphaType;
334 } else {
335 skAlphaType = kOpaque_SkAlphaType;
336 }
337 skColorType = kN32_SkColorType;
338 break;
scroggo6f29a3c2015-07-07 06:09:08 -0700339 case PNG_COLOR_TYPE_GRAY:
emmaleer21cea722015-07-10 07:48:03 -0700340 if (has_transparency_in_tRNS(png_ptr, info_ptr)) {
scroggo6f29a3c2015-07-07 06:09:08 -0700341 //FIXME: support gray with alpha as a color type
342 //convert to RGBA if there is transparentcy info in the tRNS chunk
343 png_set_tRNS_to_alpha(png_ptr);
344 png_set_gray_to_rgb(png_ptr);
345 skColorType = kN32_SkColorType;
346 skAlphaType = kUnpremul_SkAlphaType;
347 } else {
348 skColorType = kGray_8_SkColorType;
349 skAlphaType = kOpaque_SkAlphaType;
350 }
351 break;
352 case PNG_COLOR_TYPE_GRAY_ALPHA:
mtklein372d65c2016-01-27 13:01:41 -0800353 //FIXME: support gray with alpha as a color type
354 //convert to RGBA
jvanverth6c90e092015-07-02 10:35:25 -0700355 png_set_gray_to_rgb(png_ptr);
scroggo6f29a3c2015-07-07 06:09:08 -0700356 skColorType = kN32_SkColorType;
357 skAlphaType = kUnpremul_SkAlphaType;
358 break;
359 case PNG_COLOR_TYPE_RGBA:
360 skColorType = kN32_SkColorType;
361 skAlphaType = kUnpremul_SkAlphaType;
362 break;
363 default:
364 //all the color types have been covered above
365 SkASSERT(false);
scroggof24f2242015-03-03 08:59:20 -0800366 }
367
scroggo46c57472015-09-30 08:57:13 -0700368 int numberPasses = png_set_interlace_handling(png_ptr);
369 if (numberPassesPtr) {
370 *numberPassesPtr = numberPasses;
371 }
372
halcanary6950de62015-11-07 05:29:00 -0800373 // FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ).
scroggof24f2242015-03-03 08:59:20 -0800374
scroggo3eada2a2015-04-01 09:33:23 -0700375 if (imageInfo) {
scroggo6f29a3c2015-07-07 06:09:08 -0700376 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlphaType);
scroggo3eada2a2015-04-01 09:33:23 -0700377 }
scroggof24f2242015-03-03 08:59:20 -0800378 autoClean.detach();
scroggo3eada2a2015-04-01 09:33:23 -0700379 if (png_ptrp) {
380 *png_ptrp = png_ptr;
381 }
382 if (info_ptrp) {
383 *info_ptrp = info_ptr;
384 }
scroggo6f29a3c2015-07-07 06:09:08 -0700385
scroggo3eada2a2015-04-01 09:33:23 -0700386 return true;
387}
388
scroggocf98fa92015-11-23 08:14:40 -0800389SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkReader* chunkReader,
scroggo46c57472015-09-30 08:57:13 -0700390 png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses)
scroggof24f2242015-03-03 08:59:20 -0800391 : INHERITED(info, stream)
scroggocf98fa92015-11-23 08:14:40 -0800392 , fPngChunkReader(SkSafeRef(chunkReader))
scroggof24f2242015-03-03 08:59:20 -0800393 , fPng_ptr(png_ptr)
scroggo05245902015-03-25 11:11:52 -0700394 , fInfo_ptr(info_ptr)
395 , fSrcConfig(SkSwizzler::kUnknown)
scroggo46c57472015-09-30 08:57:13 -0700396 , fNumberPasses(numberPasses)
scroggo6f29a3c2015-07-07 06:09:08 -0700397 , fBitDepth(bitDepth)
msaretta4970dc2016-01-11 07:23:23 -0800398{}
scroggof24f2242015-03-03 08:59:20 -0800399
400SkPngCodec::~SkPngCodec() {
scroggo3eada2a2015-04-01 09:33:23 -0700401 this->destroyReadStruct();
402}
403
404void SkPngCodec::destroyReadStruct() {
405 if (fPng_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -0700406 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
scroggo3eada2a2015-04-01 09:33:23 -0700407 SkASSERT(fInfo_ptr);
408 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
halcanary96fcdcc2015-08-27 07:41:13 -0700409 fPng_ptr = nullptr;
410 fInfo_ptr = nullptr;
scroggo3eada2a2015-04-01 09:33:23 -0700411 }
scroggof24f2242015-03-03 08:59:20 -0800412}
413
414///////////////////////////////////////////////////////////////////////////////
415// Getting the pixels
416///////////////////////////////////////////////////////////////////////////////
417
scroggo05245902015-03-25 11:11:52 -0700418SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
msarett438b2ad2015-04-09 12:43:10 -0700419 const Options& options,
msarett9e43cab2015-04-29 07:38:43 -0700420 SkPMColor ctable[],
msarett438b2ad2015-04-09 12:43:10 -0700421 int* ctableCount) {
scroggof24f2242015-03-03 08:59:20 -0800422 // FIXME: Could we use the return value of setjmp to specify the type of
423 // error?
424 if (setjmp(png_jmpbuf(fPng_ptr))) {
scroggo230d4ac2015-03-26 07:15:55 -0700425 SkCodecPrintf("setjmp long jump!\n");
scroggof24f2242015-03-03 08:59:20 -0800426 return kInvalidInput;
427 }
mtklein372d65c2016-01-27 13:01:41 -0800428 png_read_update_info(fPng_ptr, fInfo_ptr);
scroggof24f2242015-03-03 08:59:20 -0800429
scroggo46c57472015-09-30 08:57:13 -0700430 //srcColorType was determined in read_header() which determined png color type
scroggo6f29a3c2015-07-07 06:09:08 -0700431 const SkColorType srcColorType = this->getInfo().colorType();
432
433 switch (srcColorType) {
434 case kIndex_8_SkColorType:
435 //decode palette to Skia format
436 fSrcConfig = SkSwizzler::kIndex;
scroggo9b2cdbf42015-07-10 12:07:02 -0700437 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(),
scroggo6f29a3c2015-07-07 06:09:08 -0700438 ctableCount)) {
439 return kInvalidInput;
440 }
441 break;
442 case kGray_8_SkColorType:
443 fSrcConfig = SkSwizzler::kGray;
mtklein372d65c2016-01-27 13:01:41 -0800444 break;
scroggo6f29a3c2015-07-07 06:09:08 -0700445 case kN32_SkColorType:
446 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
msarettbda86092016-01-19 10:40:12 -0800447 fSrcConfig = SkSwizzler::kRGB;
scroggo6f29a3c2015-07-07 06:09:08 -0700448 } else {
449 fSrcConfig = SkSwizzler::kRGBA;
450 }
451 break;
452 default:
453 //would have exited before now if the colorType was supported by png
454 SkASSERT(false);
mtklein372d65c2016-01-27 13:01:41 -0800455 }
msarett9e43cab2015-04-29 07:38:43 -0700456
457 // Copy the color table to the client if they request kIndex8 mode
458 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
459
460 // Create the swizzler. SkPngCodec retains ownership of the color table.
msarett99f567e2015-08-05 12:58:26 -0700461 const SkPMColor* colors = get_color_ptr(fColorTable.get());
msarettfdb47572015-10-13 12:50:14 -0700462 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, options));
scroggo05245902015-03-25 11:11:52 -0700463 if (!fSwizzler) {
scroggof24f2242015-03-03 08:59:20 -0800464 // FIXME: CreateSwizzler could fail for another reason.
465 return kUnimplemented;
466 }
scroggo05245902015-03-25 11:11:52 -0700467 return kSuccess;
468}
469
scroggo6f29a3c2015-07-07 06:09:08 -0700470
scroggob427db12015-08-12 07:24:13 -0700471bool SkPngCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -0700472 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
scroggob427db12015-08-12 07:24:13 -0700473 // succeeds, they will be repopulated, and if it fails, they will
halcanary96fcdcc2015-08-27 07:41:13 -0700474 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
scroggob427db12015-08-12 07:24:13 -0700475 // come through this function which will rewind and again attempt
476 // to reinitialize them.
477 this->destroyReadStruct();
478
479 png_structp png_ptr;
480 png_infop info_ptr;
scroggocf98fa92015-11-23 08:14:40 -0800481 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr,
482 nullptr, nullptr, nullptr)) {
scroggob427db12015-08-12 07:24:13 -0700483 return false;
scroggo58421542015-04-01 11:25:20 -0700484 }
scroggob427db12015-08-12 07:24:13 -0700485
486 fPng_ptr = png_ptr;
487 fInfo_ptr = info_ptr;
488 return true;
scroggo58421542015-04-01 11:25:20 -0700489}
490
scroggo05245902015-03-25 11:11:52 -0700491SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
msarett614aa072015-07-27 15:13:17 -0700492 size_t dstRowBytes, const Options& options,
msarette6dd0042015-10-09 11:07:34 -0700493 SkPMColor ctable[], int* ctableCount,
494 int* rowsDecoded) {
scroggo6f29a3c2015-07-07 06:09:08 -0700495 if (!conversion_possible(requestedInfo, this->getInfo())) {
496 return kInvalidConversion;
497 }
scroggob636b452015-07-22 07:16:20 -0700498 if (options.fSubset) {
499 // Subsets are not supported.
500 return kUnimplemented;
501 }
scroggo05245902015-03-25 11:11:52 -0700502
msarett9e43cab2015-04-29 07:38:43 -0700503 // Note that ctable and ctableCount may be modified if there is a color table
msarettfdb47572015-10-13 12:50:14 -0700504 const Result result = this->initializeSwizzler(requestedInfo, options, ctable, ctableCount);
scroggo05245902015-03-25 11:11:52 -0700505 if (result != kSuccess) {
506 return result;
507 }
scroggo05245902015-03-25 11:11:52 -0700508 // FIXME: Could we use the return value of setjmp to specify the type of
509 // error?
msarette6dd0042015-10-09 11:07:34 -0700510 int row = 0;
511 // This must be declared above the call to setjmp to avoid memory leaks on incomplete images.
scroggo565901d2015-12-10 10:44:13 -0800512 SkAutoTMalloc<uint8_t> storage;
scroggo05245902015-03-25 11:11:52 -0700513 if (setjmp(png_jmpbuf(fPng_ptr))) {
msarette6dd0042015-10-09 11:07:34 -0700514 // Assume that any error that occurs while reading rows is caused by an incomplete input.
515 if (fNumberPasses > 1) {
516 // FIXME (msarett): Handle incomplete interlaced pngs.
517 return kInvalidInput;
518 }
519 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium,
520 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192
521 // bytes), and if we can't fill the buffer, we immediately fail.
522 // For example, if we try to read 8192 bytes, and the image (incorrectly) only contains
523 // half that, which may have been enough to contain a non-zero number of lines, we fail
524 // when we could have decoded a few more lines and then failed.
525 // The read function that we provide for libpng has no way of indicating that we have
526 // made a partial read.
527 // Making our buffer size smaller improves our incomplete decodes, but what impact does
528 // it have on regular decode performance? Should we investigate using a different API
529 // instead of png_read_row(s)? Chromium uses png_process_data.
530 *rowsDecoded = row;
531 return kIncompleteInput;
scroggo05245902015-03-25 11:11:52 -0700532 }
533
scroggo46c57472015-09-30 08:57:13 -0700534 // FIXME: We could split these out based on subclass.
msarett614aa072015-07-27 15:13:17 -0700535 void* dstRow = dst;
scroggo05245902015-03-25 11:11:52 -0700536 if (fNumberPasses > 1) {
scroggof24f2242015-03-03 08:59:20 -0800537 const int width = requestedInfo.width();
538 const int height = requestedInfo.height();
scroggo05245902015-03-25 11:11:52 -0700539 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
msarett614aa072015-07-27 15:13:17 -0700540 const size_t srcRowBytes = width * bpp;
scroggof24f2242015-03-03 08:59:20 -0800541
542 storage.reset(width * height * bpp);
scroggo565901d2015-12-10 10:44:13 -0800543 uint8_t* const base = storage.get();
scroggof24f2242015-03-03 08:59:20 -0800544
scroggo05245902015-03-25 11:11:52 -0700545 for (int i = 0; i < fNumberPasses; i++) {
msarett614aa072015-07-27 15:13:17 -0700546 uint8_t* srcRow = base;
scroggof24f2242015-03-03 08:59:20 -0800547 for (int y = 0; y < height; y++) {
msarett614aa072015-07-27 15:13:17 -0700548 uint8_t* bmRow = srcRow;
scroggof24f2242015-03-03 08:59:20 -0800549 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1);
msarett614aa072015-07-27 15:13:17 -0700550 srcRow += srcRowBytes;
scroggof24f2242015-03-03 08:59:20 -0800551 }
552 }
553
554 // Now swizzle it.
msarett614aa072015-07-27 15:13:17 -0700555 uint8_t* srcRow = base;
scroggof24f2242015-03-03 08:59:20 -0800556 for (int y = 0; y < height; y++) {
msaretta4970dc2016-01-11 07:23:23 -0800557 fSwizzler->swizzle(dstRow, srcRow);
msarett614aa072015-07-27 15:13:17 -0700558 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
559 srcRow += srcRowBytes;
scroggof24f2242015-03-03 08:59:20 -0800560 }
561 } else {
scroggo05245902015-03-25 11:11:52 -0700562 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConfig));
scroggo565901d2015-12-10 10:44:13 -0800563 uint8_t* srcRow = storage.get();
msarette6dd0042015-10-09 11:07:34 -0700564 for (; row < requestedInfo.height(); row++) {
scroggof24f2242015-03-03 08:59:20 -0800565 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
scroggo46c57472015-09-30 08:57:13 -0700566 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetScanlines.
msaretta4970dc2016-01-11 07:23:23 -0800567 fSwizzler->swizzle(dstRow, srcRow);
msarett614aa072015-07-27 15:13:17 -0700568 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
scroggof24f2242015-03-03 08:59:20 -0800569 }
570 }
571
scroggo05245902015-03-25 11:11:52 -0700572 // FIXME: do we need substituteTranspColor? Note that we cannot do it for
573 // scanline decoding, but we could do it here. Alternatively, we could do
574 // it as we go, instead of in post-processing like SkPNGImageDecoder.
scroggof24f2242015-03-03 08:59:20 -0800575
scroggo05245902015-03-25 11:11:52 -0700576 if (setjmp(png_jmpbuf(fPng_ptr))) {
577 // We've already read all the scanlines. This is a success.
emmaleer973ae862015-07-20 13:38:44 -0700578 return kSuccess;
scroggo05245902015-03-25 11:11:52 -0700579 }
emmaleer973ae862015-07-20 13:38:44 -0700580
581 // read rest of file, and get additional comment and time chunks in info_ptr
scroggo05245902015-03-25 11:11:52 -0700582 png_read_end(fPng_ptr, fInfo_ptr);
scroggo46c57472015-09-30 08:57:13 -0700583
emmaleer973ae862015-07-20 13:38:44 -0700584 return kSuccess;
scroggo05245902015-03-25 11:11:52 -0700585}
586
msarette6dd0042015-10-09 11:07:34 -0700587uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType) const {
588 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
589 if (colorPtr) {
590 return get_color_table_fill_value(colorType, colorPtr, 0);
591 }
592 return INHERITED::onGetFillValue(colorType, alphaType);
593}
594
scroggo46c57472015-09-30 08:57:13 -0700595// Subclass of SkPngCodec which supports scanline decoding
596class SkPngScanlineDecoder : public SkPngCodec {
scroggo05245902015-03-25 11:11:52 -0700597public:
scroggo46c57472015-09-30 08:57:13 -0700598 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
scroggocf98fa92015-11-23 08:14:40 -0800599 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
600 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1)
msarettf724b992015-10-15 06:41:06 -0700601 , fSrcRow(nullptr)
scroggo1c005e42015-08-04 09:24:45 -0700602 {}
603
scroggo46c57472015-09-30 08:57:13 -0700604 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
605 SkPMColor ctable[], int* ctableCount) override {
scroggo1c005e42015-08-04 09:24:45 -0700606 if (!conversion_possible(dstInfo, this->getInfo())) {
scroggo46c57472015-09-30 08:57:13 -0700607 return kInvalidConversion;
scroggo1c005e42015-08-04 09:24:45 -0700608 }
609
scroggo46c57472015-09-30 08:57:13 -0700610 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
611 ctableCount);
612 if (result != kSuccess) {
scroggo1c005e42015-08-04 09:24:45 -0700613 return result;
614 }
615
scroggo46c57472015-09-30 08:57:13 -0700616 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig()));
scroggo565901d2015-12-10 10:44:13 -0800617 fSrcRow = fStorage.get();
scroggo1c005e42015-08-04 09:24:45 -0700618
scroggo46c57472015-09-30 08:57:13 -0700619 return kSuccess;
scroggo05245902015-03-25 11:11:52 -0700620 }
621
msarette6dd0042015-10-09 11:07:34 -0700622 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
623 // Assume that an error in libpng indicates an incomplete input.
624 int row = 0;
scroggo46c57472015-09-30 08:57:13 -0700625 if (setjmp(png_jmpbuf(this->png_ptr()))) {
scroggo230d4ac2015-03-26 07:15:55 -0700626 SkCodecPrintf("setjmp long jump!\n");
msarette6dd0042015-10-09 11:07:34 -0700627 return row;
scroggo05245902015-03-25 11:11:52 -0700628 }
629
msarett614aa072015-07-27 15:13:17 -0700630 void* dstRow = dst;
msarette6dd0042015-10-09 11:07:34 -0700631 for (; row < count; row++) {
scroggo46c57472015-09-30 08:57:13 -0700632 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
msaretta4970dc2016-01-11 07:23:23 -0800633 this->swizzler()->swizzle(dstRow, fSrcRow);
msarett614aa072015-07-27 15:13:17 -0700634 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
scroggo05245902015-03-25 11:11:52 -0700635 }
scroggo46c57472015-09-30 08:57:13 -0700636
msarette6dd0042015-10-09 11:07:34 -0700637 return row;
scroggo05245902015-03-25 11:11:52 -0700638 }
639
msarette6dd0042015-10-09 11:07:34 -0700640 bool onSkipScanlines(int count) override {
641 // Assume that an error in libpng indicates an incomplete input.
scroggo46c57472015-09-30 08:57:13 -0700642 if (setjmp(png_jmpbuf(this->png_ptr()))) {
scroggo230d4ac2015-03-26 07:15:55 -0700643 SkCodecPrintf("setjmp long jump!\n");
msarette6dd0042015-10-09 11:07:34 -0700644 return false;
scroggo05245902015-03-25 11:11:52 -0700645 }
mtklein372d65c2016-01-27 13:01:41 -0800646 //there is a potential tradeoff of memory vs speed created by putting this in a loop.
647 //calling png_read_rows in a loop is insignificantly slower than calling it once with count
emmaleer7dc91902015-05-27 08:49:04 -0700648 //as png_read_rows has it's own loop which calls png_read_row count times.
msarette6dd0042015-10-09 11:07:34 -0700649 for (int row = 0; row < count; row++) {
scroggo46c57472015-09-30 08:57:13 -0700650 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
emmaleer7dc91902015-05-27 08:49:04 -0700651 }
msarette6dd0042015-10-09 11:07:34 -0700652 return true;
scroggo05245902015-03-25 11:11:52 -0700653 }
654
scroggo05245902015-03-25 11:11:52 -0700655private:
scroggo565901d2015-12-10 10:44:13 -0800656 SkAutoTMalloc<uint8_t> fStorage;
scroggo9b2cdbf42015-07-10 12:07:02 -0700657 uint8_t* fSrcRow;
scroggo05245902015-03-25 11:11:52 -0700658
scroggo46c57472015-09-30 08:57:13 -0700659 typedef SkPngCodec INHERITED;
scroggo05245902015-03-25 11:11:52 -0700660};
661
emmaleer0a4c3cb2015-06-22 10:40:21 -0700662
scroggo46c57472015-09-30 08:57:13 -0700663class SkPngInterlacedScanlineDecoder : public SkPngCodec {
emmaleer0a4c3cb2015-06-22 10:40:21 -0700664public:
scroggo46c57472015-09-30 08:57:13 -0700665 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
scroggocf98fa92015-11-23 08:14:40 -0800666 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr,
667 int bitDepth, int numberPasses)
668 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses)
scroggo46c57472015-09-30 08:57:13 -0700669 , fHeight(-1)
scroggo1c005e42015-08-04 09:24:45 -0700670 , fCanSkipRewind(false)
scroggo1c005e42015-08-04 09:24:45 -0700671 {
scroggo46c57472015-09-30 08:57:13 -0700672 SkASSERT(numberPasses != 1);
673 }
674
675 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
msarettfdb47572015-10-13 12:50:14 -0700676 SkPMColor ctable[], int* ctableCount) override {
scroggo1c005e42015-08-04 09:24:45 -0700677 if (!conversion_possible(dstInfo, this->getInfo())) {
mtklein372d65c2016-01-27 13:01:41 -0800678 return kInvalidConversion;
scroggo1c005e42015-08-04 09:24:45 -0700679 }
680
msarettfdb47572015-10-13 12:50:14 -0700681 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
682 ctableCount);
683 if (result != kSuccess) {
scroggo1c005e42015-08-04 09:24:45 -0700684 return result;
685 }
686
scroggo1c005e42015-08-04 09:24:45 -0700687 fHeight = dstInfo.height();
scroggo46c57472015-09-30 08:57:13 -0700688 // FIXME: This need not be called on a second call to onStartScanlineDecode.
689 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig());
scroggo1c005e42015-08-04 09:24:45 -0700690 fGarbageRow.reset(fSrcRowBytes);
691 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
692 fCanSkipRewind = true;
693
694 return SkCodec::kSuccess;
695 }
696
msarette6dd0042015-10-09 11:07:34 -0700697 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
scroggo1c005e42015-08-04 09:24:45 -0700698 // rewind stream if have previously called onGetScanlines,
699 // since we need entire progressive image to get scanlines
700 if (fCanSkipRewind) {
scroggo46c57472015-09-30 08:57:13 -0700701 // We already rewound in onStartScanlineDecode, so there is no reason to rewind.
scroggo1c005e42015-08-04 09:24:45 -0700702 // Next time onGetScanlines is called, we will need to rewind.
703 fCanSkipRewind = false;
scroggo46c57472015-09-30 08:57:13 -0700704 } else {
705 // rewindIfNeeded resets fCurrScanline, since it assumes that start
706 // needs to be called again before scanline decoding. PNG scanline
707 // decoding is the exception, since it needs to rewind between
708 // calls to getScanlines. Keep track of fCurrScanline, to undo the
709 // reset.
msarette6dd0042015-10-09 11:07:34 -0700710 const int currScanline = this->nextScanline();
scroggo46c57472015-09-30 08:57:13 -0700711 // This method would never be called if currScanline is -1
712 SkASSERT(currScanline != -1);
713
714 if (!this->rewindIfNeeded()) {
715 return kCouldNotRewind;
716 }
msarettcb0d5c92015-12-03 12:23:43 -0800717 this->updateCurrScanline(currScanline);
scroggo1c005e42015-08-04 09:24:45 -0700718 }
719
scroggo46c57472015-09-30 08:57:13 -0700720 if (setjmp(png_jmpbuf(this->png_ptr()))) {
emmaleer0a4c3cb2015-06-22 10:40:21 -0700721 SkCodecPrintf("setjmp long jump!\n");
msarette6dd0042015-10-09 11:07:34 -0700722 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
723 // we may be able to report that all of the memory has been initialized. Even if we
724 // fail on the first pass, we can still report than some scanlines are initialized.
725 return 0;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700726 }
scroggo565901d2015-12-10 10:44:13 -0800727 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
728 uint8_t* storagePtr = storage.get();
emmaleer0a4c3cb2015-06-22 10:40:21 -0700729 uint8_t* srcRow;
msarette6dd0042015-10-09 11:07:34 -0700730 const int startRow = this->nextScanline();
scroggo46c57472015-09-30 08:57:13 -0700731 for (int i = 0; i < this->numberPasses(); i++) {
732 // read rows we planned to skip into garbage row
733 for (int y = 0; y < startRow; y++){
734 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700735 }
scroggo46c57472015-09-30 08:57:13 -0700736 // read rows we care about into buffer
emmaleer0a4c3cb2015-06-22 10:40:21 -0700737 srcRow = storagePtr;
738 for (int y = 0; y < count; y++) {
scroggo46c57472015-09-30 08:57:13 -0700739 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700740 srcRow += fSrcRowBytes;
741 }
scroggo46c57472015-09-30 08:57:13 -0700742 // read rows we don't want into garbage buffer
743 for (int y = 0; y < fHeight - startRow - count; y++) {
744 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700745 }
746 }
747 //swizzle the rows we care about
748 srcRow = storagePtr;
msarett614aa072015-07-27 15:13:17 -0700749 void* dstRow = dst;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700750 for (int y = 0; y < count; y++) {
msaretta4970dc2016-01-11 07:23:23 -0800751 this->swizzler()->swizzle(dstRow, srcRow);
msarett614aa072015-07-27 15:13:17 -0700752 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700753 srcRow += fSrcRowBytes;
754 }
scroggo46c57472015-09-30 08:57:13 -0700755
msarette6dd0042015-10-09 11:07:34 -0700756 return count;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700757 }
758
msarette6dd0042015-10-09 11:07:34 -0700759 bool onSkipScanlines(int count) override {
scroggo46c57472015-09-30 08:57:13 -0700760 // The non-virtual version will update fCurrScanline.
msarette6dd0042015-10-09 11:07:34 -0700761 return true;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700762 }
763
msarett5406d6f2015-08-31 06:55:13 -0700764 SkScanlineOrder onGetScanlineOrder() const override {
765 return kNone_SkScanlineOrder;
emmaleer8f4ba762015-08-14 07:44:46 -0700766 }
767
emmaleer0a4c3cb2015-06-22 10:40:21 -0700768private:
scroggo9b2cdbf42015-07-10 12:07:02 -0700769 int fHeight;
770 size_t fSrcRowBytes;
771 SkAutoMalloc fGarbageRow;
772 uint8_t* fGarbageRowPtr;
scroggo1c005e42015-08-04 09:24:45 -0700773 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
774 // is called whenever some action is taken that reads the stream and
775 // therefore the next call will require a rewind. So it modifies a boolean
776 // to note that the *next* time it is called a rewind is needed.
scroggo46c57472015-09-30 08:57:13 -0700777 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
778 // onStartScanlineDecode followed by onGetScanlines does *not* require a
779 // rewind. Since rewindIfNeeded does not have this flexibility, we need to
780 // add another layer.
scroggo1c005e42015-08-04 09:24:45 -0700781 bool fCanSkipRewind;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700782
scroggo46c57472015-09-30 08:57:13 -0700783 typedef SkPngCodec INHERITED;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700784};
785
scroggocf98fa92015-11-23 08:14:40 -0800786SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
scroggo46c57472015-09-30 08:57:13 -0700787 SkAutoTDelete<SkStream> streamDeleter(stream);
788 png_structp png_ptr;
789 png_infop info_ptr;
790 SkImageInfo imageInfo;
791 int bitDepth;
792 int numberPasses;
793
scroggocf98fa92015-11-23 08:14:40 -0800794 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitDepth,
795 &numberPasses)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700796 return nullptr;
scroggo05245902015-03-25 11:11:52 -0700797 }
798
scroggo46c57472015-09-30 08:57:13 -0700799 if (1 == numberPasses) {
scroggocf98fa92015-11-23 08:14:40 -0800800 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
801 png_ptr, info_ptr, bitDepth);
scroggo05245902015-03-25 11:11:52 -0700802 }
803
scroggocf98fa92015-11-23 08:14:40 -0800804 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
805 png_ptr, info_ptr, bitDepth, numberPasses);
scroggo05245902015-03-25 11:11:52 -0700806}