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