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