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