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