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