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