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