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