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 "SkBitmap.h"
9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h"
11 #include "SkColorSpace_Base.h"
12 #include "SkColorTable.h"
13 #include "SkMath.h"
14 #include "SkOpts.h"
15 #include "SkPngCodec.h"
16 #include "SkPoint3.h"
17 #include "SkSize.h"
18 #include "SkStream.h"
19 #include "SkSwizzler.h"
20 #include "SkTemplates.h"
21 #include "SkUtils.h"
22 
23 #include "png.h"
24 
25 // This warning triggers false postives way too often in here.
26 #if defined(__GNUC__) && !defined(__clang__)
27     #pragma GCC diagnostic ignored "-Wclobbered"
28 #endif
29 
30 #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5)
31     // This is not needed with version 1.5
32     #undef SK_GOOGLE3_PNG_HACK
33 #endif
34 
35 // FIXME (scroggo): We can use png_jumpbuf directly once Google3 is on 1.6
36 #define PNG_JMPBUF(x) png_jmpbuf((png_structp) x)
37 
38 ///////////////////////////////////////////////////////////////////////////////
39 // Callback functions
40 ///////////////////////////////////////////////////////////////////////////////
41 
fill(const SkImageInfo & info,void * dst,size_t rowBytes,uint64_t colorOrIndex,SkCodec::ZeroInitialized zeroInit)42 // When setjmp is first called, it returns 0, meaning longjmp was not called.
43 constexpr int kSetJmpOkay   = 0;
44 // An error internal to libpng.
45 constexpr int kPngError     = 1;
46 // Passed to longjmp when we have decoded as many lines as we need.
47 constexpr int kStopDecoding = 2;
48 
49 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
50     SkCodecPrintf("------ png error %s\n", msg);
51     longjmp(PNG_JMPBUF(png_ptr), kPngError);
52 }
53 
54 void sk_warning_fn(png_structp, png_const_charp msg) {
55     SkCodecPrintf("----- png warning %s\n", msg);
56 }
57 
58 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
59 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
60     SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
61     // readChunk() returning true means continue decoding
62     return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1;
63 }
64 #endif
65 
66 ///////////////////////////////////////////////////////////////////////////////
67 // Helpers
68 ///////////////////////////////////////////////////////////////////////////////
69 
70 class AutoCleanPng : public SkNoncopyable {
71 public:
72     /*
73      *  This class does not take ownership of stream or reader, but if codecPtr
74      *  is non-NULL, and decodeBounds succeeds, it will have created a new
75      *  SkCodec (pointed to by *codecPtr) which will own/ref them, as well as
76      *  the png_ptr and info_ptr.
77      */
78     AutoCleanPng(png_structp png_ptr, SkStream* stream, SkPngChunkReader* reader,
79             SkCodec** codecPtr)
80         : fPng_ptr(png_ptr)
81         , fInfo_ptr(nullptr)
82         , fDecodedBounds(false)
83         , fReadHeader(false)
84         , fStream(stream)
85         , fChunkReader(reader)
86         , fOutCodec(codecPtr)
87     {}
88 
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 
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     bool                fDecodedBounds;
120     bool                fReadHeader;
121     SkStream*           fStream;
122     SkPngChunkReader*   fChunkReader;
123     SkCodec**           fOutCodec;
124 
125     /**
126      *  Supplied to libpng to call when it has read enough data to determine
127      *  bounds.
128      */
129     static void InfoCallback(png_structp png_ptr, png_infop) {
130         // png_get_progressive_ptr returns the pointer we set on the png_ptr with
131         // png_set_progressive_read_fn
132         static_cast<AutoCleanPng*>(png_get_progressive_ptr(png_ptr))->infoCallback();
133     }
134 
135     void infoCallback();
136 
137 #ifdef SK_GOOGLE3_PNG_HACK
138 // public so it can be called by SkPngCodec::rereadHeaderIfNecessary().
139 public:
140 #endif
141     void releasePngPtrs() {
142         fPng_ptr = nullptr;
143         fInfo_ptr = nullptr;
144     }
145 };
146 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
147 
148 bool AutoCleanPng::decodeBounds() {
149     if (setjmp(PNG_JMPBUF(fPng_ptr))) {
150         return false;
151     }
152 
153     png_set_progressive_read_fn(fPng_ptr, this, InfoCallback, nullptr, nullptr);
154 
155     // Arbitrary buffer size, though note that it matches (below)
156     // SkPngCodec::processData(). FIXME: Can we better suit this to the size of
157     // the PNG header?
158     constexpr size_t kBufferSize = 4096;
159     char buffer[kBufferSize];
160 
161     while (true) {
162         const size_t bytesRead = fStream->read(buffer, kBufferSize);
163         if (!bytesRead) {
164             // We have read to the end of the input without decoding bounds.
165             break;
166         }
167 
168         png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, bytesRead);
169         if (fReadHeader) {
170             break;
171         }
172     }
173 
174     // For safety, clear the pointer to this object.
175     png_set_progressive_read_fn(fPng_ptr, nullptr, nullptr, nullptr, nullptr);
176     return fDecodedBounds;
177 }
178 
179 void SkPngCodec::processData() {
180     switch (setjmp(PNG_JMPBUF(fPng_ptr))) {
181         case kPngError:
182             // There was an error. Stop processing data.
183             // FIXME: Do we need to discard png_ptr?
184             return;
185         case kStopDecoding:
186             // We decoded all the lines we want.
187             return;
188         case kSetJmpOkay:
189             // Everything is okay.
190             break;
191         default:
192             // No other values should be passed to longjmp.
193             SkASSERT(false);
194     }
195 
196     // Arbitrary buffer size
197     constexpr size_t kBufferSize = 4096;
198     char buffer[kBufferSize];
199 
200     while (true) {
201         const size_t bytesRead = this->stream()->read(buffer, kBufferSize);
202         png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, bytesRead);
203 
204         if (!bytesRead) {
205             // We have read to the end of the input. Note that we quit *after*
206             // calling png_process_data, because decodeBounds may have told
207             // libpng to save the remainder of the buffer, in which case
208             // png_process_data will process the saved buffer, though the
209             // stream has no more to read.
210             break;
211         }
212     }
213 }
214 
215 // Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
216 bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) {
217 
218     int numColors;
219     png_color* palette;
220     if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
221         return false;
222     }
223 
224     // Contents depend on tableColorType and our choice of if/when to premultiply:
225     // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA }
226     SkPMColor colorTable[256];
227     SkColorType tableColorType = fColorXform ? kRGBA_8888_SkColorType : dstInfo.colorType();
228 
229     png_bytep alphas;
230     int numColorsWithAlpha = 0;
231     if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
232         // If we are performing a color xform, it will handle the premultiply.  Otherwise,
233         // we'll do it here.
234         bool premultiply =  !fColorXform && needs_premul(dstInfo, this->getInfo());
235 
236         // Choose which function to use to create the color table. If the final destination's
237         // colortype is unpremultiplied, the color table will store unpremultiplied colors.
238         PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType);
239 
240         for (int i = 0; i < numColorsWithAlpha; i++) {
241             // We don't have a function in SkOpts that combines a set of alphas with a set
242             // of RGBs.  We could write one, but it's hardly worth it, given that this
243             // is such a small fraction of the total decode time.
244             colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
245             palette++;
246         }
247     }
248 
249     if (numColorsWithAlpha < numColors) {
250         // The optimized code depends on a 3-byte png_color struct with the colors
251         // in RGB order.  These checks make sure it is safe to use.
252         static_assert(3 == sizeof(png_color), "png_color struct has changed.  Opts are broken.");
253 #ifdef SK_DEBUG
254         SkASSERT(&palette->red < &palette->green);
255         SkASSERT(&palette->green < &palette->blue);
256 #endif
257 
258         if (is_rgba(tableColorType)) {
259             SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, palette,
260                     numColors - numColorsWithAlpha);
261         } else {
262             SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, palette,
263                     numColors - numColorsWithAlpha);
264         }
265     }
266 
267     // If we are not decoding to F16, we can color xform now and store the results
268     // in the color table.
269     if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) {
270         SkColorSpaceXform::ColorFormat xformColorFormat = is_rgba(dstInfo.colorType()) ?
271                 SkColorSpaceXform::kRGBA_8888_ColorFormat :
272                 SkColorSpaceXform::kBGRA_8888_ColorFormat;
273         SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(),
274                                                         this->getInfo().alphaType());
275         fColorXform->apply(colorTable, colorTable, numColors, xformColorFormat,
276                            SkColorSpaceXform::kRGBA_8888_ColorFormat, xformAlphaType);
277     }
278 
279     // Pad the color table with the last color in the table (or black) in the case that
280     // invalid pixel indices exceed the number of colors in the table.
281     const int maxColors = 1 << fBitDepth;
282     if (numColors < maxColors) {
283         SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK;
284         sk_memset32(colorTable + numColors, lastColor, maxColors - numColors);
285     }
286 
287     // Set the new color count.
288     if (ctableCount != nullptr) {
289         *ctableCount = maxColors;
290     }
291 
292     fColorTable.reset(new SkColorTable(colorTable, maxColors));
293     return true;
294 }
295 
296 ///////////////////////////////////////////////////////////////////////////////
297 // Creation
298 ///////////////////////////////////////////////////////////////////////////////
299 
300 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
301     return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
302 }
303 
304 #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
305 
306 static float png_fixed_point_to_float(png_fixed_point x) {
307     // We multiply by the same factor that libpng used to convert
308     // fixed point -> double.  Since we want floats, we choose to
309     // do the conversion ourselves rather than convert
310     // fixed point -> double -> float.
311     return ((float) x) * 0.00001f;
312 }
313 
314 static float png_inverted_fixed_point_to_float(png_fixed_point x) {
315     // This is necessary because the gAMA chunk actually stores 1/gamma.
316     return 1.0f / png_fixed_point_to_float(x);
317 }
318 
319 static constexpr float gSRGB_toXYZD50[] {
320     0.4358f, 0.3853f, 0.1430f,    // Rx, Gx, Bx
321     0.2224f, 0.7170f, 0.0606f,    // Ry, Gy, Gz
322     0.0139f, 0.0971f, 0.7139f,    // Rz, Gz, Bz
323 };
324 
325 static bool convert_to_D50(SkMatrix44* toXYZD50, float toXYZ[9], float whitePoint[2]) {
326     float wX = whitePoint[0];
327     float wY = whitePoint[1];
328     if (wX < 0.0f || wY < 0.0f || (wX + wY > 1.0f)) {
329         return false;
330     }
331 
332     // Calculate the XYZ illuminant.  Call this the src illuminant.
333     float wZ = 1.0f - wX - wY;
334     float scale = 1.0f / wY;
335     // TODO (msarett):
336     // What are common src illuminants?  I'm guessing we will almost always see D65.  Should
337     // we go ahead and save a precomputed D65->D50 Bradford matrix?  Should we exit early if
338     // if the src illuminant is D50?
339     SkVector3 srcXYZ = SkVector3::Make(wX * scale, 1.0f, wZ * scale);
340 
341     // The D50 illuminant.
342     SkVector3 dstXYZ = SkVector3::Make(0.96422f, 1.0f, 0.82521f);
343 
344     // Calculate the chromatic adaptation matrix.  We will use the Bradford method, thus
345     // the matrices below.  The Bradford method is used by Adobe and is widely considered
346     // to be the best.
347     // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
348     SkMatrix mA, mAInv;
349     mA.setAll(0.8951f, 0.2664f, -0.1614f, -0.7502f, 1.7135f, 0.0367f, 0.0389f, -0.0685f, 1.0296f);
350     mAInv.setAll(0.9869929f, -0.1470543f, 0.1599627f, 0.4323053f, 0.5183603f, 0.0492912f,
351                  -0.0085287f, 0.0400428f, 0.9684867f);
352 
353     // Map illuminant into cone response domain.
354     SkVector3 srcCone;
355     srcCone.fX = mA[0] * srcXYZ.fX + mA[1] * srcXYZ.fY + mA[2] * srcXYZ.fZ;
356     srcCone.fY = mA[3] * srcXYZ.fX + mA[4] * srcXYZ.fY + mA[5] * srcXYZ.fZ;
357     srcCone.fZ = mA[6] * srcXYZ.fX + mA[7] * srcXYZ.fY + mA[8] * srcXYZ.fZ;
358     SkVector3 dstCone;
359     dstCone.fX = mA[0] * dstXYZ.fX + mA[1] * dstXYZ.fY + mA[2] * dstXYZ.fZ;
360     dstCone.fY = mA[3] * dstXYZ.fX + mA[4] * dstXYZ.fY + mA[5] * dstXYZ.fZ;
361     dstCone.fZ = mA[6] * dstXYZ.fX + mA[7] * dstXYZ.fY + mA[8] * dstXYZ.fZ;
362 
363     SkMatrix DXToD50;
364     DXToD50.setIdentity();
365     DXToD50[0] = dstCone.fX / srcCone.fX;
366     DXToD50[4] = dstCone.fY / srcCone.fY;
367     DXToD50[8] = dstCone.fZ / srcCone.fZ;
368     DXToD50.postConcat(mAInv);
369     DXToD50.preConcat(mA);
370 
371     SkMatrix toXYZ3x3;
372     toXYZ3x3.setAll(toXYZ[0], toXYZ[3], toXYZ[6], toXYZ[1], toXYZ[4], toXYZ[7], toXYZ[2], toXYZ[5],
373                     toXYZ[8]);
374     toXYZ3x3.postConcat(DXToD50);
375 
376     toXYZD50->set3x3(toXYZ3x3[0], toXYZ3x3[3], toXYZ3x3[6],
377                      toXYZ3x3[1], toXYZ3x3[4], toXYZ3x3[7],
378                      toXYZ3x3[2], toXYZ3x3[5], toXYZ3x3[8]);
379     return true;
380 }
381 
382 #endif // LIBPNG >= 1.6
383 
384 // Returns a colorSpace object that represents any color space information in
385 // the encoded data.  If the encoded data contains no color space, this will
386 // return NULL.
387 sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
388 
389 #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
390 
391     // First check for an ICC profile
392     png_bytep profile;
393     png_uint_32 length;
394     // The below variables are unused, however, we need to pass them in anyway or
395     // png_get_iCCP() will return nothing.
396     // Could knowing the |name| of the profile ever be interesting?  Maybe for debugging?
397     png_charp name;
398     // The |compression| is uninteresting since:
399     //   (1) libpng has already decompressed the profile for us.
400     //   (2) "deflate" is the only mode of decompression that libpng supports.
401     int compression;
402     if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
403             &length)) {
404         return SkColorSpace::NewICC(profile, length);
405     }
406 
407     // Second, check for sRGB.
408     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
409 
410         // sRGB chunks also store a rendering intent: Absolute, Relative,
411         // Perceptual, and Saturation.
412         // FIXME (msarett): Extract this information from the sRGB chunk once
413         //                  we are able to handle this information in
414         //                  SkColorSpace.
415         return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
416     }
417 
418     // Next, check for chromaticities.
419     png_fixed_point toXYZFixed[9];
420     float toXYZ[9];
421     png_fixed_point whitePointFixed[2];
422     float whitePoint[2];
423     png_fixed_point gamma;
424     float gammas[3];
425     if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &toXYZFixed[0], &toXYZFixed[1], &toXYZFixed[2],
426                                &toXYZFixed[3], &toXYZFixed[4], &toXYZFixed[5], &toXYZFixed[6],
427                                &toXYZFixed[7], &toXYZFixed[8]) &&
428         png_get_cHRM_fixed(png_ptr, info_ptr, &whitePointFixed[0], &whitePointFixed[1], nullptr,
429                            nullptr, nullptr, nullptr, nullptr, nullptr))
430     {
431         for (int i = 0; i < 9; i++) {
432             toXYZ[i] = png_fixed_point_to_float(toXYZFixed[i]);
433         }
434         whitePoint[0] = png_fixed_point_to_float(whitePointFixed[0]);
435         whitePoint[1] = png_fixed_point_to_float(whitePointFixed[1]);
436 
437         SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
438         if (!convert_to_D50(&toXYZD50, toXYZ, whitePoint)) {
439             toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
440         }
441 
442         if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
443             float value = png_inverted_fixed_point_to_float(gamma);
444             gammas[0] = value;
445             gammas[1] = value;
446             gammas[2] = value;
447 
448             return SkColorSpace_Base::NewRGB(gammas, toXYZD50);
449         }
450 
451         // Default to sRGB gamma if the image has color space information,
452         // but does not specify gamma.
453         return SkColorSpace::NewRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
454     }
455 
456     // Last, check for gamma.
457     if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
458 
459         // Set the gammas.
460         float value = png_inverted_fixed_point_to_float(gamma);
461         gammas[0] = value;
462         gammas[1] = value;
463         gammas[2] = value;
464 
465         // Since there is no cHRM, we will guess sRGB gamut.
466         SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
467         toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
468 
469         return SkColorSpace_Base::NewRGB(gammas, toXYZD50);
470     }
471 
472 #endif // LIBPNG >= 1.6
473 
474     // Report that there is no color space information in the PNG.  SkPngCodec is currently
475     // implemented to guess sRGB in this case.
476     return nullptr;
477 }
478 
479 void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
480     switch (fXformMode) {
481         case kSwizzleOnly_XformMode:
482             break;
483         case kColorOnly_XformMode:
484             // Intentional fall through.  A swizzler hasn't been created yet, but one will
485             // be created later if we are sampling.  We'll go ahead and allocate
486             // enough memory to swizzle if necessary.
487         case kSwizzleColor_XformMode: {
488             const size_t colorXformBytes = dstInfo.width() * sizeof(uint32_t);
489             fStorage.reset(colorXformBytes);
490             fColorXformSrcRow = (uint32_t*) fStorage.get();
491             break;
492         }
493     }
494 }
495 
496 void SkPngCodec::applyXformRow(void* dst, const void* src) {
497     const SkColorSpaceXform::ColorFormat srcColorFormat = SkColorSpaceXform::kRGBA_8888_ColorFormat;
498     switch (fXformMode) {
499         case kSwizzleOnly_XformMode:
500             fSwizzler->swizzle(dst, (const uint8_t*) src);
501             break;
502         case kColorOnly_XformMode:
503             fColorXform->apply(dst, (const uint32_t*) src, fXformWidth, fXformColorFormat,
504                                srcColorFormat, fXformAlphaType);
505             break;
506         case kSwizzleColor_XformMode:
507             fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src);
508             fColorXform->apply(dst, fColorXformSrcRow, fXformWidth, fXformColorFormat,
509                                srcColorFormat, fXformAlphaType);
510             break;
511     }
512 }
513 
514 class SkPngNormalDecoder : public SkPngCodec {
515 public:
516     SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStream* stream,
517             SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
518         : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth)
519         , fLinesDecoded(0)
520         , fDst(nullptr)
521         , fRowBytes(0)
522         , fFirstRow(0)
523         , fLastRow(0)
524     {}
525 
526     static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
527         GetDecoder(png_ptr)->allRowsCallback(row, rowNum);
528     }
529 
530     static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
531         GetDecoder(png_ptr)->rowCallback(row, rowNum);
532     }
533 
534 #ifdef SK_GOOGLE3_PNG_HACK
535     static void RereadInfoCallback(png_structp png_ptr, png_infop) {
536         GetDecoder(png_ptr)->rereadInfoCallback();
537     }
538 #endif
539 
540 private:
541     int                         fLinesDecoded; // FIXME: Move to baseclass?
542     void*                       fDst;
543     size_t                      fRowBytes;
544 
545     // Variables for partial decode
546     int                         fFirstRow;  // FIXME: Move to baseclass?
547     int                         fLastRow;
548 
549     typedef SkPngCodec INHERITED;
550 
551     static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) {
552         return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr));
553     }
554 
555     Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
556         const int height = this->getInfo().height();
557         png_progressive_info_ptr callback = nullptr;
558 #ifdef SK_GOOGLE3_PNG_HACK
559         callback = RereadInfoCallback;
560 #endif
561         png_set_progressive_read_fn(this->png_ptr(), this, callback, AllRowsCallback, nullptr);
562         fDst = dst;
563         fRowBytes = rowBytes;
564 
565         fLinesDecoded = 0;
566 
567         this->processData();
568 
569         if (fLinesDecoded == height) {
570             return SkCodec::kSuccess;
571         }
572 
573         if (rowsDecoded) {
574             *rowsDecoded = fLinesDecoded;
575         }
576 
577         return SkCodec::kIncompleteInput;
578     }
579 
580     void allRowsCallback(png_bytep row, int rowNum) {
581         SkASSERT(rowNum - fFirstRow == fLinesDecoded);
582         fLinesDecoded++;
583         this->applyXformRow(fDst, row);
584         fDst = SkTAddOffset<void>(fDst, fRowBytes);
585     }
586 
587     void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
588         png_progressive_info_ptr callback = nullptr;
589 #ifdef SK_GOOGLE3_PNG_HACK
590         callback = RereadInfoCallback;
591 #endif
592         png_set_progressive_read_fn(this->png_ptr(), this, callback, RowCallback, nullptr);
593         fFirstRow = firstRow;
594         fLastRow = lastRow;
595         fDst = dst;
596         fRowBytes = rowBytes;
597         fLinesDecoded = 0;
598     }
599 
600     SkCodec::Result decode(int* rowsDecoded) override {
601         this->processData();
602 
603         if (fLinesDecoded == fLastRow - fFirstRow + 1) {
604             return SkCodec::kSuccess;
605         }
606 
607         if (rowsDecoded) {
608             *rowsDecoded = fLinesDecoded;
609         }
610 
611         return SkCodec::kIncompleteInput;
612     }
613 
614     void rowCallback(png_bytep row, int rowNum) {
615         if (rowNum < fFirstRow) {
616             // Ignore this row.
617             return;
618         }
619 
620         SkASSERT(rowNum <= fLastRow);
621 
622         // If there is no swizzler, all rows are needed.
623         if (!this->swizzler() || this->swizzler()->rowNeeded(fLinesDecoded)) {
624             this->applyXformRow(fDst, row);
625             fDst = SkTAddOffset<void>(fDst, fRowBytes);
626         }
627 
628         fLinesDecoded++;
629 
630         if (rowNum == fLastRow) {
631             // Fake error to stop decoding scanlines.
632             longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
633         }
634     }
635 };
636 
637 class SkPngInterlacedDecoder : public SkPngCodec {
638 public:
639     SkPngInterlacedDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
640             SkStream* stream, SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr,
641             int bitDepth, int numberPasses)
642         : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth)
643         , fNumberPasses(numberPasses)
644         , fFirstRow(0)
645         , fLastRow(0)
646         , fLinesDecoded(0)
647         , fInterlacedComplete(false)
648         , fPng_rowbytes(0)
649     {}
650 
651     static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int pass) {
652         auto decoder = static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr));
653         decoder->interlacedRowCallback(row, rowNum, pass);
654     }
655 
656 #ifdef SK_GOOGLE3_PNG_HACK
657     static void RereadInfoInterlacedCallback(png_structp png_ptr, png_infop) {
658         static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr))->rereadInfoInterlaced();
659     }
660 #endif
661 
662 private:
663     const int               fNumberPasses;
664     int                     fFirstRow;
665     int                     fLastRow;
666     void*                   fDst;
667     size_t                  fRowBytes;
668     int                     fLinesDecoded;
669     bool                    fInterlacedComplete;
670     size_t                  fPng_rowbytes;
671     SkAutoTMalloc<png_byte> fInterlaceBuffer;
672 
673     typedef SkPngCodec INHERITED;
674 
675 #ifdef SK_GOOGLE3_PNG_HACK
676     void rereadInfoInterlaced() {
677         this->rereadInfoCallback();
678         // Note: This allocates more memory than necessary, if we are sampling/subset.
679         this->setUpInterlaceBuffer(this->getInfo().height());
680     }
681 #endif
682 
683     // FIXME: Currently sharing interlaced callback for all rows and subset. It's not
684     // as expensive as the subset version of non-interlaced, but it still does extra
685     // work.
686     void interlacedRowCallback(png_bytep row, int rowNum, int pass) {
687         if (rowNum < fFirstRow || rowNum > fLastRow) {
688             // Ignore this row
689             return;
690         }
691 
692         png_bytep oldRow = fInterlaceBuffer.get() + (rowNum - fFirstRow) * fPng_rowbytes;
693         png_progressive_combine_row(this->png_ptr(), oldRow, row);
694 
695         if (0 == pass) {
696             // The first pass initializes all rows.
697             SkASSERT(row);
698             SkASSERT(fLinesDecoded == rowNum - fFirstRow);
699             fLinesDecoded++;
700         } else {
701             SkASSERT(fLinesDecoded == fLastRow - fFirstRow + 1);
702             if (fNumberPasses - 1 == pass && rowNum == fLastRow) {
703                 // Last pass, and we have read all of the rows we care about. Note that
704                 // we do not care about reading anything beyond the end of the image (or
705                 // beyond the last scanline requested).
706                 fInterlacedComplete = true;
707                 // Fake error to stop decoding scanlines.
708                 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
709             }
710         }
711     }
712 
713     SkCodec::Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
714         const int height = this->getInfo().height();
715         this->setUpInterlaceBuffer(height);
716         png_progressive_info_ptr callback = nullptr;
717 #ifdef SK_GOOGLE3_PNG_HACK
718         callback = RereadInfoInterlacedCallback;
719 #endif
720         png_set_progressive_read_fn(this->png_ptr(), this, callback, InterlacedRowCallback,
721                                     nullptr);
722 
723         fFirstRow = 0;
724         fLastRow = height - 1;
725         fLinesDecoded = 0;
726 
727         this->processData();
728 
729         png_bytep srcRow = fInterlaceBuffer.get();
730         // FIXME: When resuming, this may rewrite rows that did not change.
731         for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) {
732             this->applyXformRow(dst, srcRow);
733             dst = SkTAddOffset<void>(dst, rowBytes);
734             srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes);
735         }
736         if (fInterlacedComplete) {
737             return SkCodec::kSuccess;
738         }
739 
740         if (rowsDecoded) {
741             *rowsDecoded = fLinesDecoded;
742         }
743 
744         return SkCodec::kIncompleteInput;
745     }
746 
747     void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
748         // FIXME: We could skip rows in the interlace buffer that we won't put in the output.
749         this->setUpInterlaceBuffer(lastRow - firstRow + 1);
750         png_progressive_info_ptr callback = nullptr;
751 #ifdef SK_GOOGLE3_PNG_HACK
752         callback = RereadInfoInterlacedCallback;
753 #endif
754         png_set_progressive_read_fn(this->png_ptr(), this, callback, InterlacedRowCallback, nullptr);
755         fFirstRow = firstRow;
756         fLastRow = lastRow;
757         fDst = dst;
758         fRowBytes = rowBytes;
759         fLinesDecoded = 0;
760     }
761 
762     SkCodec::Result decode(int* rowsDecoded) override {
763         this->processData();
764 
765         // Now apply Xforms on all the rows that were decoded.
766         if (!fLinesDecoded) {
767             return SkCodec::kIncompleteInput;
768         }
769         const int lastRow = fLinesDecoded + fFirstRow - 1;
770         SkASSERT(lastRow <= fLastRow);
771 
772         // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it
773         // may be too tricky/expensive to handle that correctly.
774         png_bytep srcRow = fInterlaceBuffer.get();
775         const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1;
776         void* dst = fDst;
777         for (int rowNum = fFirstRow; rowNum <= lastRow; rowNum += sampleY) {
778             this->applyXformRow(dst, srcRow);
779             dst = SkTAddOffset<void>(dst, fRowBytes);
780             srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY);
781         }
782 
783         if (fInterlacedComplete) {
784             return SkCodec::kSuccess;
785         }
786 
787         if (rowsDecoded) {
788             *rowsDecoded = fLinesDecoded;
789         }
790         return SkCodec::kIncompleteInput;
791     }
792 
793     void setUpInterlaceBuffer(int height) {
794         fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr());
795         fInterlaceBuffer.reset(fPng_rowbytes * height);
796         fInterlacedComplete = false;
797     }
798 };
799 
800 #ifdef SK_GOOGLE3_PNG_HACK
801 bool SkPngCodec::rereadHeaderIfNecessary() {
802     if (!fNeedsToRereadHeader) {
803         return true;
804     }
805 
806     // On the first call, we'll need to rewind ourselves. Future calls will
807     // have already rewound in rewindIfNecessary.
808     if (this->stream()->getPosition() > 0) {
809         this->stream()->rewind();
810     }
811 
812     this->destroyReadStruct();
813     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
814                                                  sk_error_fn, sk_warning_fn);
815     if (!png_ptr) {
816         return false;
817     }
818 
819     // Only use the AutoCleanPng to delete png_ptr as necessary.
820     // (i.e. not for reading bounds etc.)
821     AutoCleanPng autoClean(png_ptr, nullptr, nullptr, nullptr);
822 
823     png_infop info_ptr = png_create_info_struct(png_ptr);
824     if (info_ptr == nullptr) {
825         return false;
826     }
827 
828     autoClean.setInfoPtr(info_ptr);
829 
830 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
831     // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
832     // This needs to be installed before we read the png header.  Android may store ninepatch
833     // chunks in the header.
834     if (fPngChunkReader.get()) {
835         png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
836         png_set_read_user_chunk_fn(png_ptr, (png_voidp) fPngChunkReader.get(), sk_read_user_chunk);
837     }
838 #endif
839 
840     fPng_ptr = png_ptr;
841     fInfo_ptr = info_ptr;
842     autoClean.releasePngPtrs();
843     fNeedsToRereadHeader = false;
844     return true;
845 }
846 #endif // SK_GOOGLE3_PNG_HACK
847 
848 // Reads the header and initializes the output fields, if not NULL.
849 //
850 // @param stream Input data. Will be read to get enough information to properly
851 //      setup the codec.
852 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
853 //      If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
854 //      expected to continue to own it for the lifetime of the png_ptr.
855 // @param outCodec Optional output variable.  If non-NULL, will be set to a new
856 //      SkPngCodec on success.
857 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new
858 //      png_structp on success.
859 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new
860 //      png_infop on success;
861 // @return true on success, in which case the caller is responsible for calling
862 //      png_destroy_read_struct(png_ptrp, info_ptrp).
863 //      If it returns false, the passed in fields (except stream) are unchanged.
864 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec** outCodec,
865                         png_structp* png_ptrp, png_infop* info_ptrp) {
866     // The image is known to be a PNG. Decode enough to know the SkImageInfo.
867     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
868                                                  sk_error_fn, sk_warning_fn);
869     if (!png_ptr) {
870         return false;
871     }
872 
873     AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec);
874 
875     png_infop info_ptr = png_create_info_struct(png_ptr);
876     if (info_ptr == nullptr) {
877         return false;
878     }
879 
880     autoClean.setInfoPtr(info_ptr);
881 
882     // FIXME: Could we use the return value of setjmp to specify the type of
883     // error?
884     if (setjmp(PNG_JMPBUF(png_ptr))) {
885         return false;
886     }
887 
888 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
889     // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
890     // This needs to be installed before we read the png header.  Android may store ninepatch
891     // chunks in the header.
892     if (chunkReader) {
893         png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
894         png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
895     }
896 #endif
897 
898     const bool decodedBounds = autoClean.decodeBounds();
899 
900     if (!decodedBounds) {
901         return false;
902     }
903 
904     // On success, decodeBounds releases ownership of png_ptr and info_ptr.
905     if (png_ptrp) {
906         *png_ptrp = png_ptr;
907     }
908     if (info_ptrp) {
909         *info_ptrp = info_ptr;
910     }
911 
912     // decodeBounds takes care of setting outCodec
913     if (outCodec) {
914         SkASSERT(*outCodec);
915     }
916     return true;
917 }
918 
919 // FIXME (scroggo): Once SK_GOOGLE3_PNG_HACK is no more, this method can be inline in
920 // AutoCleanPng::infoCallback
921 static void general_info_callback(png_structp png_ptr, png_infop info_ptr,
922                                   SkEncodedInfo::Color* outColor, SkEncodedInfo::Alpha* outAlpha) {
923     png_uint_32 origWidth, origHeight;
924     int bitDepth, encodedColorType;
925     png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
926                  &encodedColorType, nullptr, nullptr, nullptr);
927 
928     // Tell libpng to strip 16 bit/color files down to 8 bits/color.
929     // TODO: Should we handle this in SkSwizzler?  Could this also benefit
930     //       RAW decodes?
931     if (bitDepth == 16) {
932         SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
933         png_set_strip_16(png_ptr);
934     }
935 
936     // Now determine the default colorType and alphaType and set the required transforms.
937     // Often, we depend on SkSwizzler to perform any transforms that we need.  However, we
938     // still depend on libpng for many of the rare and PNG-specific cases.
939     SkEncodedInfo::Color color;
940     SkEncodedInfo::Alpha alpha;
941     switch (encodedColorType) {
942         case PNG_COLOR_TYPE_PALETTE:
943             // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
944             // byte into separate bytes (useful for paletted and grayscale images).
945             if (bitDepth < 8) {
946                 // TODO: Should we use SkSwizzler here?
947                 png_set_packing(png_ptr);
948             }
949 
950             color = SkEncodedInfo::kPalette_Color;
951             // Set the alpha depending on if a transparency chunk exists.
952             alpha = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
953                     SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha;
954             break;
955         case PNG_COLOR_TYPE_RGB:
956             if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
957                 // Convert to RGBA if transparency chunk exists.
958                 png_set_tRNS_to_alpha(png_ptr);
959                 color = SkEncodedInfo::kRGBA_Color;
960                 alpha = SkEncodedInfo::kBinary_Alpha;
961             } else {
962                 color = SkEncodedInfo::kRGB_Color;
963                 alpha = SkEncodedInfo::kOpaque_Alpha;
964             }
965             break;
966         case PNG_COLOR_TYPE_GRAY:
967             // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
968             if (bitDepth < 8) {
969                 // TODO: Should we use SkSwizzler here?
970                 png_set_expand_gray_1_2_4_to_8(png_ptr);
971             }
972 
973             if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
974                 png_set_tRNS_to_alpha(png_ptr);
975                 color = SkEncodedInfo::kGrayAlpha_Color;
976                 alpha = SkEncodedInfo::kBinary_Alpha;
977             } else {
978                 color = SkEncodedInfo::kGray_Color;
979                 alpha = SkEncodedInfo::kOpaque_Alpha;
980             }
981             break;
982         case PNG_COLOR_TYPE_GRAY_ALPHA:
983             color = SkEncodedInfo::kGrayAlpha_Color;
984             alpha = SkEncodedInfo::kUnpremul_Alpha;
985             break;
986         case PNG_COLOR_TYPE_RGBA:
987             color = SkEncodedInfo::kRGBA_Color;
988             alpha = SkEncodedInfo::kUnpremul_Alpha;
989             break;
990         default:
991             // All the color types have been covered above.
992             SkASSERT(false);
993             color = SkEncodedInfo::kRGBA_Color;
994             alpha = SkEncodedInfo::kUnpremul_Alpha;
995     }
996     if (outColor) {
997         *outColor = color;
998     }
999     if (outAlpha) {
1000         *outAlpha = alpha;
1001     }
1002 }
1003 
1004 #ifdef SK_GOOGLE3_PNG_HACK
1005 void SkPngCodec::rereadInfoCallback() {
1006     general_info_callback(fPng_ptr, fInfo_ptr, nullptr, nullptr);
1007     png_set_interlace_handling(fPng_ptr);
1008     png_read_update_info(fPng_ptr, fInfo_ptr);
1009 }
1010 #endif
1011 
1012 void AutoCleanPng::infoCallback() {
1013     SkEncodedInfo::Color color;
1014     SkEncodedInfo::Alpha alpha;
1015     general_info_callback(fPng_ptr, fInfo_ptr, &color, &alpha);
1016 
1017     const int numberPasses = png_set_interlace_handling(fPng_ptr);
1018 
1019     fReadHeader = true;
1020     fDecodedBounds = true;
1021 #ifndef SK_GOOGLE3_PNG_HACK
1022     // 1 tells libpng to save any extra data. We may be able to be more efficient by saving
1023     // it ourselves.
1024     png_process_data_pause(fPng_ptr, 1);
1025 #else
1026     // Hack to make png_process_data stop.
1027     fPng_ptr->buffer_size = 0;
1028 #endif
1029     if (fOutCodec) {
1030         SkASSERT(nullptr == *fOutCodec);
1031         sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr);
1032         if (!colorSpace) {
1033             // Treat unmarked pngs as sRGB.
1034             colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
1035         }
1036 
1037         SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, 8);
1038         // FIXME (scroggo): Once we get rid of SK_GOOGLE3_PNG_HACK, general_info_callback can
1039         // be inlined, so these values will already be set.
1040         png_uint_32 origWidth = png_get_image_width(fPng_ptr, fInfo_ptr);
1041         png_uint_32 origHeight = png_get_image_height(fPng_ptr, fInfo_ptr);
1042         png_byte bitDepth = png_get_bit_depth(fPng_ptr, fInfo_ptr);
1043         SkImageInfo imageInfo = encodedInfo.makeImageInfo(origWidth, origHeight, colorSpace);
1044 
1045         if (SkEncodedInfo::kOpaque_Alpha == alpha) {
1046             png_color_8p sigBits;
1047             if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
1048                 if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
1049                     // Recommend a decode to 565 if the sBIT indicates 565.
1050                     imageInfo = imageInfo.makeColorType(kRGB_565_SkColorType);
1051                 }
1052             }
1053         }
1054 
1055         if (1 == numberPasses) {
1056             *fOutCodec = new SkPngNormalDecoder(encodedInfo, imageInfo, fStream,
1057                     fChunkReader, fPng_ptr, fInfo_ptr, bitDepth);
1058         } else {
1059             *fOutCodec = new SkPngInterlacedDecoder(encodedInfo, imageInfo, fStream,
1060                     fChunkReader, fPng_ptr, fInfo_ptr, bitDepth, numberPasses);
1061         }
1062     }
1063 
1064 
1065     // Release the pointers, which are now owned by the codec or the caller is expected to
1066     // take ownership.
1067     this->releasePngPtrs();
1068 }
1069 
1070 SkPngCodec::SkPngCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
1071                        SkStream* stream, SkPngChunkReader* chunkReader, void* png_ptr,
1072                        void* info_ptr, int bitDepth)
1073     : INHERITED(encodedInfo, imageInfo, stream)
1074     , fPngChunkReader(SkSafeRef(chunkReader))
1075     , fPng_ptr(png_ptr)
1076     , fInfo_ptr(info_ptr)
1077     , fColorXformSrcRow(nullptr)
1078     , fBitDepth(bitDepth)
1079 #ifdef SK_GOOGLE3_PNG_HACK
1080     , fNeedsToRereadHeader(true)
1081 #endif
1082 {}
1083 
1084 SkPngCodec::~SkPngCodec() {
1085     this->destroyReadStruct();
1086 }
1087 
1088 void SkPngCodec::destroyReadStruct() {
1089     if (fPng_ptr) {
1090         // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
1091         SkASSERT(fInfo_ptr);
1092         png_destroy_read_struct((png_struct**)&fPng_ptr, (png_info**)&fInfo_ptr, nullptr);
1093         fPng_ptr = nullptr;
1094         fInfo_ptr = nullptr;
1095     }
1096 }
1097 
1098 ///////////////////////////////////////////////////////////////////////////////
1099 // Getting the pixels
1100 ///////////////////////////////////////////////////////////////////////////////
1101 
1102 bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options,
1103                                   SkPMColor ctable[], int* ctableCount) {
1104     if (setjmp(PNG_JMPBUF((png_struct*)fPng_ptr))) {
1105         SkCodecPrintf("Failed on png_read_update_info.\n");
1106         return false;
1107     }
1108     png_read_update_info(fPng_ptr, fInfo_ptr);
1109 
1110     // Reset fSwizzler and fColorXform.  We can't do this in onRewind() because the
1111     // interlaced scanline decoder may need to rewind.
1112     fSwizzler.reset(nullptr);
1113     fColorXform = nullptr;
1114 
1115     if (needs_color_xform(dstInfo, this->getInfo())) {
1116         fColorXform = SkColorSpaceXform::New(this->getInfo().colorSpace(), dstInfo.colorSpace());
1117         SkASSERT(fColorXform);
1118     }
1119 
1120     // If the image is RGBA and we have a color xform, we can skip the swizzler.
1121     // FIXME (msarett):
1122     // Support more input types to fColorXform (ex: RGB, Gray) and skip the swizzler more often.
1123     if (fColorXform && SkEncodedInfo::kRGBA_Color == this->getEncodedInfo().color() &&
1124         !options.fSubset)
1125     {
1126         fXformMode = kColorOnly_XformMode;
1127         return true;
1128     }
1129 
1130     if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
1131         if (!this->createColorTable(dstInfo, ctableCount)) {
1132             return false;
1133         }
1134     }
1135 
1136     // Copy the color table to the client if they request kIndex8 mode.
1137     copy_color_table(dstInfo, fColorTable, ctable, ctableCount);
1138 
1139     this->initializeSwizzler(dstInfo, options);
1140     return true;
1141 }
1142 
1143 void SkPngCodec::initializeXformParams() {
1144     switch (fXformMode) {
1145         case kColorOnly_XformMode:
1146             fXformColorFormat = select_xform_format(this->dstInfo().colorType());
1147             fXformAlphaType = select_xform_alpha(this->dstInfo().alphaType(),
1148                                                  this->getInfo().alphaType());
1149             fXformWidth = this->dstInfo().width();
1150             break;
1151         case kSwizzleColor_XformMode:
1152             fXformColorFormat = select_xform_format(this->dstInfo().colorType());
1153             fXformAlphaType = select_xform_alpha(this->dstInfo().alphaType(),
1154                                                  this->getInfo().alphaType());
1155             fXformWidth = this->swizzler()->swizzleWidth();
1156             break;
1157         default:
1158             break;
1159     }
1160 }
1161 
1162 static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) {
1163     // We will apply the color xform when reading the color table, unless F16 is requested.
1164     return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
1165 }
1166 
1167 void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
1168     SkImageInfo swizzlerInfo = dstInfo;
1169     Options swizzlerOptions = options;
1170     fXformMode = kSwizzleOnly_XformMode;
1171     if (fColorXform && apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color())) {
1172         swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
1173         if (kPremul_SkAlphaType == dstInfo.alphaType()) {
1174             swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
1175         }
1176 
1177         fXformMode = kSwizzleColor_XformMode;
1178 
1179         // Here, we swizzle into temporary memory, which is not zero initialized.
1180         // FIXME (msarett):
1181         // Is this a problem?
1182         swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized;
1183     }
1184 
1185     const SkPMColor* colors = get_color_ptr(fColorTable.get());
1186     fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, swizzlerInfo,
1187                                                swizzlerOptions));
1188     SkASSERT(fSwizzler);
1189 }
1190 
1191 SkSampler* SkPngCodec::getSampler(bool createIfNecessary) {
1192     if (fSwizzler || !createIfNecessary) {
1193         return fSwizzler;
1194     }
1195 
1196     this->initializeSwizzler(this->dstInfo(), this->options());
1197     return fSwizzler;
1198 }
1199 
1200 bool SkPngCodec::onRewind() {
1201 #ifdef SK_GOOGLE3_PNG_HACK
1202     fNeedsToRereadHeader = true;
1203     return true;
1204 #else
1205     // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
1206     // succeeds, they will be repopulated, and if it fails, they will
1207     // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
1208     // come through this function which will rewind and again attempt
1209     // to reinitialize them.
1210     this->destroyReadStruct();
1211 
1212     png_structp png_ptr;
1213     png_infop info_ptr;
1214     if (!read_header(this->stream(), fPngChunkReader.get(), nullptr, &png_ptr, &info_ptr)) {
1215         return false;
1216     }
1217 
1218     fPng_ptr = png_ptr;
1219     fInfo_ptr = info_ptr;
1220     return true;
1221 #endif
1222 }
1223 
1224 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
1225                                         size_t rowBytes, const Options& options,
1226                                         SkPMColor ctable[], int* ctableCount,
1227                                         int* rowsDecoded) {
1228     if (!conversion_possible(dstInfo, this->getInfo()) ||
1229         !this->initializeXforms(dstInfo, options, ctable, ctableCount))
1230     {
1231         return kInvalidConversion;
1232     }
1233 #ifdef SK_GOOGLE3_PNG_HACK
1234     // Note that this is done after initializeXforms. Otherwise that method
1235     // would not have png_ptr to use.
1236     if (!this->rereadHeaderIfNecessary()) {
1237         return kCouldNotRewind;
1238     }
1239 #endif
1240 
1241     if (options.fSubset) {
1242         return kUnimplemented;
1243     }
1244 
1245     this->allocateStorage(dstInfo);
1246     this->initializeXformParams();
1247     return this->decodeAllRows(dst, rowBytes, rowsDecoded);
1248 }
1249 
1250 SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
1251         void* dst, size_t rowBytes, const SkCodec::Options& options,
1252         SkPMColor* ctable, int* ctableCount) {
1253     if (!conversion_possible(dstInfo, this->getInfo()) ||
1254         !this->initializeXforms(dstInfo, options, ctable, ctableCount))
1255     {
1256         return kInvalidConversion;
1257     }
1258 #ifdef SK_GOOGLE3_PNG_HACK
1259     // See note in onGetPixels.
1260     if (!this->rereadHeaderIfNecessary()) {
1261         return kCouldNotRewind;
1262     }
1263 #endif
1264 
1265     this->allocateStorage(dstInfo);
1266 
1267     int firstRow, lastRow;
1268     if (options.fSubset) {
1269         firstRow = options.fSubset->top();
1270         lastRow = options.fSubset->bottom() - 1;
1271     } else {
1272         firstRow = 0;
1273         lastRow = dstInfo.height() - 1;
1274     }
1275     this->setRange(firstRow, lastRow, dst, rowBytes);
1276     return kSuccess;
1277 }
1278 
1279 SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) {
1280     // FIXME: Only necessary on the first call.
1281     this->initializeXformParams();
1282 
1283     return this->decode(rowsDecoded);
1284 }
1285 
1286 uint64_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const {
1287     const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
1288     if (colorPtr) {
1289         SkAlphaType alphaType = select_xform_alpha(dstInfo.alphaType(),
1290                                                    this->getInfo().alphaType());
1291         return get_color_table_fill_value(dstInfo.colorType(), alphaType, colorPtr, 0,
1292                                           fColorXform.get());
1293     }
1294     return INHERITED::onGetFillValue(dstInfo);
1295 }
1296 
1297 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
1298     SkAutoTDelete<SkStream> streamDeleter(stream);
1299 
1300     SkCodec* outCodec = nullptr;
1301     if (read_header(streamDeleter.get(), chunkReader, &outCodec, nullptr, nullptr)) {
1302         // Codec has taken ownership of the stream.
1303         SkASSERT(outCodec);
1304         streamDeleter.release();
1305         return outCodec;
1306     }
1307 
1308     return nullptr;
1309 }
1310