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