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