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