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