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