1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkBitmap.h"
9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h"
11 #include "SkColorSpace_Base.h"
12 #include "SkColorTable.h"
13 #include "SkMath.h"
14 #include "SkOpts.h"
15 #include "SkPngCodec.h"
16 #include "SkPoint3.h"
17 #include "SkSize.h"
18 #include "SkStream.h"
19 #include "SkSwizzler.h"
20 #include "SkTemplates.h"
21 #include "SkUtils.h"
22
23 #include "png.h"
24
25 // This warning triggers false postives way too often in here.
26 #if defined(__GNUC__) && !defined(__clang__)
27 #pragma GCC diagnostic ignored "-Wclobbered"
28 #endif
29
30 #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5)
31 // This is not needed with version 1.5
32 #undef SK_GOOGLE3_PNG_HACK
33 #endif
34
35 // FIXME (scroggo): We can use png_jumpbuf directly once Google3 is on 1.6
36 #define PNG_JMPBUF(x) png_jmpbuf((png_structp) x)
37
38 ///////////////////////////////////////////////////////////////////////////////
39 // Callback functions
40 ///////////////////////////////////////////////////////////////////////////////
41
fill(const SkImageInfo & info,void * dst,size_t rowBytes,uint64_t colorOrIndex,SkCodec::ZeroInitialized zeroInit)42 // When setjmp is first called, it returns 0, meaning longjmp was not called.
43 constexpr int kSetJmpOkay = 0;
44 // An error internal to libpng.
45 constexpr int kPngError = 1;
46 // Passed to longjmp when we have decoded as many lines as we need.
47 constexpr int kStopDecoding = 2;
48
49 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
50 SkCodecPrintf("------ png error %s\n", msg);
51 longjmp(PNG_JMPBUF(png_ptr), kPngError);
52 }
53
54 void sk_warning_fn(png_structp, png_const_charp msg) {
55 SkCodecPrintf("----- png warning %s\n", msg);
56 }
57
58 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
59 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
60 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
61 // readChunk() returning true means continue decoding
62 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1;
63 }
64 #endif
65
66 ///////////////////////////////////////////////////////////////////////////////
67 // Helpers
68 ///////////////////////////////////////////////////////////////////////////////
69
70 class AutoCleanPng : public SkNoncopyable {
71 public:
72 /*
73 * This class does not take ownership of stream or reader, but if codecPtr
74 * is non-NULL, and decodeBounds succeeds, it will have created a new
75 * SkCodec (pointed to by *codecPtr) which will own/ref them, as well as
76 * the png_ptr and info_ptr.
77 */
78 AutoCleanPng(png_structp png_ptr, SkStream* stream, SkPngChunkReader* reader,
79 SkCodec** codecPtr)
80 : fPng_ptr(png_ptr)
81 , fInfo_ptr(nullptr)
82 , fDecodedBounds(false)
83 , fReadHeader(false)
84 , fStream(stream)
85 , fChunkReader(reader)
86 , fOutCodec(codecPtr)
87 {}
88
89 ~AutoCleanPng() {
90 // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
91 if (fPng_ptr) {
92 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
93 png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
94 }
95 }
96
97 void setInfoPtr(png_infop info_ptr) {
98 SkASSERT(nullptr == fInfo_ptr);
99 fInfo_ptr = info_ptr;
100 }
101
102 /**
103 * Reads enough of the input stream to decode the bounds.
104 * @return false if the stream is not a valid PNG (or too short).
105 * true if it read enough of the stream to determine the bounds.
106 * In the latter case, the stream may have been read beyond the
107 * point to determine the bounds, and the png_ptr will have saved
108 * any extra data. Further, if the codecPtr supplied to the
109 * constructor was not NULL, it will now point to a new SkCodec,
110 * which owns (or refs, in the case of the SkPngChunkReader) the
111 * inputs. If codecPtr was NULL, the png_ptr and info_ptr are
112 * unowned, and it is up to the caller to destroy them.
113 */
114 bool decodeBounds();
115
116 private:
117 png_structp fPng_ptr;
118 png_infop fInfo_ptr;
119 bool fDecodedBounds;
120 bool fReadHeader;
121 SkStream* fStream;
122 SkPngChunkReader* fChunkReader;
123 SkCodec** fOutCodec;
124
125 /**
126 * Supplied to libpng to call when it has read enough data to determine
127 * bounds.
128 */
129 static void InfoCallback(png_structp png_ptr, png_infop) {
130 // png_get_progressive_ptr returns the pointer we set on the png_ptr with
131 // png_set_progressive_read_fn
132 static_cast<AutoCleanPng*>(png_get_progressive_ptr(png_ptr))->infoCallback();
133 }
134
135 void infoCallback();
136
137 #ifdef SK_GOOGLE3_PNG_HACK
138 // public so it can be called by SkPngCodec::rereadHeaderIfNecessary().
139 public:
140 #endif
141 void releasePngPtrs() {
142 fPng_ptr = nullptr;
143 fInfo_ptr = nullptr;
144 }
145 };
146 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
147
148 bool AutoCleanPng::decodeBounds() {
149 if (setjmp(PNG_JMPBUF(fPng_ptr))) {
150 return false;
151 }
152
153 png_set_progressive_read_fn(fPng_ptr, this, InfoCallback, nullptr, nullptr);
154
155 // Arbitrary buffer size, though note that it matches (below)
156 // SkPngCodec::processData(). FIXME: Can we better suit this to the size of
157 // the PNG header?
158 constexpr size_t kBufferSize = 4096;
159 char buffer[kBufferSize];
160
161 while (true) {
162 const size_t bytesRead = fStream->read(buffer, kBufferSize);
163 if (!bytesRead) {
164 // We have read to the end of the input without decoding bounds.
165 break;
166 }
167
168 png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, bytesRead);
169 if (fReadHeader) {
170 break;
171 }
172 }
173
174 // For safety, clear the pointer to this object.
175 png_set_progressive_read_fn(fPng_ptr, nullptr, nullptr, nullptr, nullptr);
176 return fDecodedBounds;
177 }
178
179 void SkPngCodec::processData() {
180 switch (setjmp(PNG_JMPBUF(fPng_ptr))) {
181 case kPngError:
182 // There was an error. Stop processing data.
183 // FIXME: Do we need to discard png_ptr?
184 return;
185 case kStopDecoding:
186 // We decoded all the lines we want.
187 return;
188 case kSetJmpOkay:
189 // Everything is okay.
190 break;
191 default:
192 // No other values should be passed to longjmp.
193 SkASSERT(false);
194 }
195
196 // Arbitrary buffer size
197 constexpr size_t kBufferSize = 4096;
198 char buffer[kBufferSize];
199
200 while (true) {
201 const size_t bytesRead = this->stream()->read(buffer, kBufferSize);
202 png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, bytesRead);
203
204 if (!bytesRead) {
205 // We have read to the end of the input. Note that we quit *after*
206 // calling png_process_data, because decodeBounds may have told
207 // libpng to save the remainder of the buffer, in which case
208 // png_process_data will process the saved buffer, though the
209 // stream has no more to read.
210 break;
211 }
212 }
213 }
214
215 // Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
216 bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) {
217
218 int numColors;
219 png_color* palette;
220 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
221 return false;
222 }
223
224 // Contents depend on tableColorType and our choice of if/when to premultiply:
225 // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA }
226 SkPMColor colorTable[256];
227 SkColorType tableColorType = fColorXform ? kRGBA_8888_SkColorType : dstInfo.colorType();
228
229 png_bytep alphas;
230 int numColorsWithAlpha = 0;
231 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
232 // If we are performing a color xform, it will handle the premultiply. Otherwise,
233 // we'll do it here.
234 bool premultiply = !fColorXform && needs_premul(dstInfo, this->getInfo());
235
236 // Choose which function to use to create the color table. If the final destination's
237 // colortype is unpremultiplied, the color table will store unpremultiplied colors.
238 PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType);
239
240 for (int i = 0; i < numColorsWithAlpha; i++) {
241 // We don't have a function in SkOpts that combines a set of alphas with a set
242 // of RGBs. We could write one, but it's hardly worth it, given that this
243 // is such a small fraction of the total decode time.
244 colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
245 palette++;
246 }
247 }
248
249 if (numColorsWithAlpha < numColors) {
250 // The optimized code depends on a 3-byte png_color struct with the colors
251 // in RGB order. These checks make sure it is safe to use.
252 static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts are broken.");
253 #ifdef SK_DEBUG
254 SkASSERT(&palette->red < &palette->green);
255 SkASSERT(&palette->green < &palette->blue);
256 #endif
257
258 if (is_rgba(tableColorType)) {
259 SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, palette,
260 numColors - numColorsWithAlpha);
261 } else {
262 SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, palette,
263 numColors - numColorsWithAlpha);
264 }
265 }
266
267 // If we are not decoding to F16, we can color xform now and store the results
268 // in the color table.
269 if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) {
270 SkColorSpaceXform::ColorFormat xformColorFormat = is_rgba(dstInfo.colorType()) ?
271 SkColorSpaceXform::kRGBA_8888_ColorFormat :
272 SkColorSpaceXform::kBGRA_8888_ColorFormat;
273 SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(),
274 this->getInfo().alphaType());
275 fColorXform->apply(colorTable, colorTable, numColors, xformColorFormat,
276 SkColorSpaceXform::kRGBA_8888_ColorFormat, xformAlphaType);
277 }
278
279 // Pad the color table with the last color in the table (or black) in the case that
280 // invalid pixel indices exceed the number of colors in the table.
281 const int maxColors = 1 << fBitDepth;
282 if (numColors < maxColors) {
283 SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK;
284 sk_memset32(colorTable + numColors, lastColor, maxColors - numColors);
285 }
286
287 // Set the new color count.
288 if (ctableCount != nullptr) {
289 *ctableCount = maxColors;
290 }
291
292 fColorTable.reset(new SkColorTable(colorTable, maxColors));
293 return true;
294 }
295
296 ///////////////////////////////////////////////////////////////////////////////
297 // Creation
298 ///////////////////////////////////////////////////////////////////////////////
299
300 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
301 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
302 }
303
304 #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
305
306 static float png_fixed_point_to_float(png_fixed_point x) {
307 // We multiply by the same factor that libpng used to convert
308 // fixed point -> double. Since we want floats, we choose to
309 // do the conversion ourselves rather than convert
310 // fixed point -> double -> float.
311 return ((float) x) * 0.00001f;
312 }
313
314 static float png_inverted_fixed_point_to_float(png_fixed_point x) {
315 // This is necessary because the gAMA chunk actually stores 1/gamma.
316 return 1.0f / png_fixed_point_to_float(x);
317 }
318
319 static constexpr float gSRGB_toXYZD50[] {
320 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx
321 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz
322 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz
323 };
324
325 static bool convert_to_D50(SkMatrix44* toXYZD50, float toXYZ[9], float whitePoint[2]) {
326 float wX = whitePoint[0];
327 float wY = whitePoint[1];
328 if (wX < 0.0f || wY < 0.0f || (wX + wY > 1.0f)) {
329 return false;
330 }
331
332 // Calculate the XYZ illuminant. Call this the src illuminant.
333 float wZ = 1.0f - wX - wY;
334 float scale = 1.0f / wY;
335 // TODO (msarett):
336 // What are common src illuminants? I'm guessing we will almost always see D65. Should
337 // we go ahead and save a precomputed D65->D50 Bradford matrix? Should we exit early if
338 // if the src illuminant is D50?
339 SkVector3 srcXYZ = SkVector3::Make(wX * scale, 1.0f, wZ * scale);
340
341 // The D50 illuminant.
342 SkVector3 dstXYZ = SkVector3::Make(0.96422f, 1.0f, 0.82521f);
343
344 // Calculate the chromatic adaptation matrix. We will use the Bradford method, thus
345 // the matrices below. The Bradford method is used by Adobe and is widely considered
346 // to be the best.
347 // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
348 SkMatrix mA, mAInv;
349 mA.setAll(0.8951f, 0.2664f, -0.1614f, -0.7502f, 1.7135f, 0.0367f, 0.0389f, -0.0685f, 1.0296f);
350 mAInv.setAll(0.9869929f, -0.1470543f, 0.1599627f, 0.4323053f, 0.5183603f, 0.0492912f,
351 -0.0085287f, 0.0400428f, 0.9684867f);
352
353 // Map illuminant into cone response domain.
354 SkVector3 srcCone;
355 srcCone.fX = mA[0] * srcXYZ.fX + mA[1] * srcXYZ.fY + mA[2] * srcXYZ.fZ;
356 srcCone.fY = mA[3] * srcXYZ.fX + mA[4] * srcXYZ.fY + mA[5] * srcXYZ.fZ;
357 srcCone.fZ = mA[6] * srcXYZ.fX + mA[7] * srcXYZ.fY + mA[8] * srcXYZ.fZ;
358 SkVector3 dstCone;
359 dstCone.fX = mA[0] * dstXYZ.fX + mA[1] * dstXYZ.fY + mA[2] * dstXYZ.fZ;
360 dstCone.fY = mA[3] * dstXYZ.fX + mA[4] * dstXYZ.fY + mA[5] * dstXYZ.fZ;
361 dstCone.fZ = mA[6] * dstXYZ.fX + mA[7] * dstXYZ.fY + mA[8] * dstXYZ.fZ;
362
363 SkMatrix DXToD50;
364 DXToD50.setIdentity();
365 DXToD50[0] = dstCone.fX / srcCone.fX;
366 DXToD50[4] = dstCone.fY / srcCone.fY;
367 DXToD50[8] = dstCone.fZ / srcCone.fZ;
368 DXToD50.postConcat(mAInv);
369 DXToD50.preConcat(mA);
370
371 SkMatrix toXYZ3x3;
372 toXYZ3x3.setAll(toXYZ[0], toXYZ[3], toXYZ[6], toXYZ[1], toXYZ[4], toXYZ[7], toXYZ[2], toXYZ[5],
373 toXYZ[8]);
374 toXYZ3x3.postConcat(DXToD50);
375
376 toXYZD50->set3x3(toXYZ3x3[0], toXYZ3x3[3], toXYZ3x3[6],
377 toXYZ3x3[1], toXYZ3x3[4], toXYZ3x3[7],
378 toXYZ3x3[2], toXYZ3x3[5], toXYZ3x3[8]);
379 return true;
380 }
381
382 #endif // LIBPNG >= 1.6
383
384 // Returns a colorSpace object that represents any color space information in
385 // the encoded data. If the encoded data contains no color space, this will
386 // return NULL.
387 sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
388
389 #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
390
391 // First check for an ICC profile
392 png_bytep profile;
393 png_uint_32 length;
394 // The below variables are unused, however, we need to pass them in anyway or
395 // png_get_iCCP() will return nothing.
396 // Could knowing the |name| of the profile ever be interesting? Maybe for debugging?
397 png_charp name;
398 // The |compression| is uninteresting since:
399 // (1) libpng has already decompressed the profile for us.
400 // (2) "deflate" is the only mode of decompression that libpng supports.
401 int compression;
402 if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
403 &length)) {
404 return SkColorSpace::NewICC(profile, length);
405 }
406
407 // Second, check for sRGB.
408 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
409
410 // sRGB chunks also store a rendering intent: Absolute, Relative,
411 // Perceptual, and Saturation.
412 // FIXME (msarett): Extract this information from the sRGB chunk once
413 // we are able to handle this information in
414 // SkColorSpace.
415 return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
416 }
417
418 // Next, check for chromaticities.
419 png_fixed_point toXYZFixed[9];
420 float toXYZ[9];
421 png_fixed_point whitePointFixed[2];
422 float whitePoint[2];
423 png_fixed_point gamma;
424 float gammas[3];
425 if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &toXYZFixed[0], &toXYZFixed[1], &toXYZFixed[2],
426 &toXYZFixed[3], &toXYZFixed[4], &toXYZFixed[5], &toXYZFixed[6],
427 &toXYZFixed[7], &toXYZFixed[8]) &&
428 png_get_cHRM_fixed(png_ptr, info_ptr, &whitePointFixed[0], &whitePointFixed[1], nullptr,
429 nullptr, nullptr, nullptr, nullptr, nullptr))
430 {
431 for (int i = 0; i < 9; i++) {
432 toXYZ[i] = png_fixed_point_to_float(toXYZFixed[i]);
433 }
434 whitePoint[0] = png_fixed_point_to_float(whitePointFixed[0]);
435 whitePoint[1] = png_fixed_point_to_float(whitePointFixed[1]);
436
437 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
438 if (!convert_to_D50(&toXYZD50, toXYZ, whitePoint)) {
439 toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
440 }
441
442 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
443 float value = png_inverted_fixed_point_to_float(gamma);
444 gammas[0] = value;
445 gammas[1] = value;
446 gammas[2] = value;
447
448 return SkColorSpace_Base::NewRGB(gammas, toXYZD50);
449 }
450
451 // Default to sRGB gamma if the image has color space information,
452 // but does not specify gamma.
453 return SkColorSpace::NewRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
454 }
455
456 // Last, check for gamma.
457 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
458
459 // Set the gammas.
460 float value = png_inverted_fixed_point_to_float(gamma);
461 gammas[0] = value;
462 gammas[1] = value;
463 gammas[2] = value;
464
465 // Since there is no cHRM, we will guess sRGB gamut.
466 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
467 toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
468
469 return SkColorSpace_Base::NewRGB(gammas, toXYZD50);
470 }
471
472 #endif // LIBPNG >= 1.6
473
474 // Report that there is no color space information in the PNG. SkPngCodec is currently
475 // implemented to guess sRGB in this case.
476 return nullptr;
477 }
478
479 void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
480 switch (fXformMode) {
481 case kSwizzleOnly_XformMode:
482 break;
483 case kColorOnly_XformMode:
484 // Intentional fall through. A swizzler hasn't been created yet, but one will
485 // be created later if we are sampling. We'll go ahead and allocate
486 // enough memory to swizzle if necessary.
487 case kSwizzleColor_XformMode: {
488 const size_t colorXformBytes = dstInfo.width() * sizeof(uint32_t);
489 fStorage.reset(colorXformBytes);
490 fColorXformSrcRow = (uint32_t*) fStorage.get();
491 break;
492 }
493 }
494 }
495
496 void SkPngCodec::applyXformRow(void* dst, const void* src) {
497 const SkColorSpaceXform::ColorFormat srcColorFormat = SkColorSpaceXform::kRGBA_8888_ColorFormat;
498 switch (fXformMode) {
499 case kSwizzleOnly_XformMode:
500 fSwizzler->swizzle(dst, (const uint8_t*) src);
501 break;
502 case kColorOnly_XformMode:
503 fColorXform->apply(dst, (const uint32_t*) src, fXformWidth, fXformColorFormat,
504 srcColorFormat, fXformAlphaType);
505 break;
506 case kSwizzleColor_XformMode:
507 fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src);
508 fColorXform->apply(dst, fColorXformSrcRow, fXformWidth, fXformColorFormat,
509 srcColorFormat, fXformAlphaType);
510 break;
511 }
512 }
513
514 class SkPngNormalDecoder : public SkPngCodec {
515 public:
516 SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStream* stream,
517 SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
518 : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth)
519 , fLinesDecoded(0)
520 , fDst(nullptr)
521 , fRowBytes(0)
522 , fFirstRow(0)
523 , fLastRow(0)
524 {}
525
526 static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
527 GetDecoder(png_ptr)->allRowsCallback(row, rowNum);
528 }
529
530 static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
531 GetDecoder(png_ptr)->rowCallback(row, rowNum);
532 }
533
534 #ifdef SK_GOOGLE3_PNG_HACK
535 static void RereadInfoCallback(png_structp png_ptr, png_infop) {
536 GetDecoder(png_ptr)->rereadInfoCallback();
537 }
538 #endif
539
540 private:
541 int fLinesDecoded; // FIXME: Move to baseclass?
542 void* fDst;
543 size_t fRowBytes;
544
545 // Variables for partial decode
546 int fFirstRow; // FIXME: Move to baseclass?
547 int fLastRow;
548
549 typedef SkPngCodec INHERITED;
550
551 static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) {
552 return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr));
553 }
554
555 Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
556 const int height = this->getInfo().height();
557 png_progressive_info_ptr callback = nullptr;
558 #ifdef SK_GOOGLE3_PNG_HACK
559 callback = RereadInfoCallback;
560 #endif
561 png_set_progressive_read_fn(this->png_ptr(), this, callback, AllRowsCallback, nullptr);
562 fDst = dst;
563 fRowBytes = rowBytes;
564
565 fLinesDecoded = 0;
566
567 this->processData();
568
569 if (fLinesDecoded == height) {
570 return SkCodec::kSuccess;
571 }
572
573 if (rowsDecoded) {
574 *rowsDecoded = fLinesDecoded;
575 }
576
577 return SkCodec::kIncompleteInput;
578 }
579
580 void allRowsCallback(png_bytep row, int rowNum) {
581 SkASSERT(rowNum - fFirstRow == fLinesDecoded);
582 fLinesDecoded++;
583 this->applyXformRow(fDst, row);
584 fDst = SkTAddOffset<void>(fDst, fRowBytes);
585 }
586
587 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
588 png_progressive_info_ptr callback = nullptr;
589 #ifdef SK_GOOGLE3_PNG_HACK
590 callback = RereadInfoCallback;
591 #endif
592 png_set_progressive_read_fn(this->png_ptr(), this, callback, RowCallback, nullptr);
593 fFirstRow = firstRow;
594 fLastRow = lastRow;
595 fDst = dst;
596 fRowBytes = rowBytes;
597 fLinesDecoded = 0;
598 }
599
600 SkCodec::Result decode(int* rowsDecoded) override {
601 this->processData();
602
603 if (fLinesDecoded == fLastRow - fFirstRow + 1) {
604 return SkCodec::kSuccess;
605 }
606
607 if (rowsDecoded) {
608 *rowsDecoded = fLinesDecoded;
609 }
610
611 return SkCodec::kIncompleteInput;
612 }
613
614 void rowCallback(png_bytep row, int rowNum) {
615 if (rowNum < fFirstRow) {
616 // Ignore this row.
617 return;
618 }
619
620 SkASSERT(rowNum <= fLastRow);
621
622 // If there is no swizzler, all rows are needed.
623 if (!this->swizzler() || this->swizzler()->rowNeeded(fLinesDecoded)) {
624 this->applyXformRow(fDst, row);
625 fDst = SkTAddOffset<void>(fDst, fRowBytes);
626 }
627
628 fLinesDecoded++;
629
630 if (rowNum == fLastRow) {
631 // Fake error to stop decoding scanlines.
632 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
633 }
634 }
635 };
636
637 class SkPngInterlacedDecoder : public SkPngCodec {
638 public:
639 SkPngInterlacedDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
640 SkStream* stream, SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr,
641 int bitDepth, int numberPasses)
642 : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth)
643 , fNumberPasses(numberPasses)
644 , fFirstRow(0)
645 , fLastRow(0)
646 , fLinesDecoded(0)
647 , fInterlacedComplete(false)
648 , fPng_rowbytes(0)
649 {}
650
651 static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int pass) {
652 auto decoder = static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr));
653 decoder->interlacedRowCallback(row, rowNum, pass);
654 }
655
656 #ifdef SK_GOOGLE3_PNG_HACK
657 static void RereadInfoInterlacedCallback(png_structp png_ptr, png_infop) {
658 static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr))->rereadInfoInterlaced();
659 }
660 #endif
661
662 private:
663 const int fNumberPasses;
664 int fFirstRow;
665 int fLastRow;
666 void* fDst;
667 size_t fRowBytes;
668 int fLinesDecoded;
669 bool fInterlacedComplete;
670 size_t fPng_rowbytes;
671 SkAutoTMalloc<png_byte> fInterlaceBuffer;
672
673 typedef SkPngCodec INHERITED;
674
675 #ifdef SK_GOOGLE3_PNG_HACK
676 void rereadInfoInterlaced() {
677 this->rereadInfoCallback();
678 // Note: This allocates more memory than necessary, if we are sampling/subset.
679 this->setUpInterlaceBuffer(this->getInfo().height());
680 }
681 #endif
682
683 // FIXME: Currently sharing interlaced callback for all rows and subset. It's not
684 // as expensive as the subset version of non-interlaced, but it still does extra
685 // work.
686 void interlacedRowCallback(png_bytep row, int rowNum, int pass) {
687 if (rowNum < fFirstRow || rowNum > fLastRow) {
688 // Ignore this row
689 return;
690 }
691
692 png_bytep oldRow = fInterlaceBuffer.get() + (rowNum - fFirstRow) * fPng_rowbytes;
693 png_progressive_combine_row(this->png_ptr(), oldRow, row);
694
695 if (0 == pass) {
696 // The first pass initializes all rows.
697 SkASSERT(row);
698 SkASSERT(fLinesDecoded == rowNum - fFirstRow);
699 fLinesDecoded++;
700 } else {
701 SkASSERT(fLinesDecoded == fLastRow - fFirstRow + 1);
702 if (fNumberPasses - 1 == pass && rowNum == fLastRow) {
703 // Last pass, and we have read all of the rows we care about. Note that
704 // we do not care about reading anything beyond the end of the image (or
705 // beyond the last scanline requested).
706 fInterlacedComplete = true;
707 // Fake error to stop decoding scanlines.
708 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
709 }
710 }
711 }
712
713 SkCodec::Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
714 const int height = this->getInfo().height();
715 this->setUpInterlaceBuffer(height);
716 png_progressive_info_ptr callback = nullptr;
717 #ifdef SK_GOOGLE3_PNG_HACK
718 callback = RereadInfoInterlacedCallback;
719 #endif
720 png_set_progressive_read_fn(this->png_ptr(), this, callback, InterlacedRowCallback,
721 nullptr);
722
723 fFirstRow = 0;
724 fLastRow = height - 1;
725 fLinesDecoded = 0;
726
727 this->processData();
728
729 png_bytep srcRow = fInterlaceBuffer.get();
730 // FIXME: When resuming, this may rewrite rows that did not change.
731 for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) {
732 this->applyXformRow(dst, srcRow);
733 dst = SkTAddOffset<void>(dst, rowBytes);
734 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes);
735 }
736 if (fInterlacedComplete) {
737 return SkCodec::kSuccess;
738 }
739
740 if (rowsDecoded) {
741 *rowsDecoded = fLinesDecoded;
742 }
743
744 return SkCodec::kIncompleteInput;
745 }
746
747 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
748 // FIXME: We could skip rows in the interlace buffer that we won't put in the output.
749 this->setUpInterlaceBuffer(lastRow - firstRow + 1);
750 png_progressive_info_ptr callback = nullptr;
751 #ifdef SK_GOOGLE3_PNG_HACK
752 callback = RereadInfoInterlacedCallback;
753 #endif
754 png_set_progressive_read_fn(this->png_ptr(), this, callback, InterlacedRowCallback, nullptr);
755 fFirstRow = firstRow;
756 fLastRow = lastRow;
757 fDst = dst;
758 fRowBytes = rowBytes;
759 fLinesDecoded = 0;
760 }
761
762 SkCodec::Result decode(int* rowsDecoded) override {
763 this->processData();
764
765 // Now apply Xforms on all the rows that were decoded.
766 if (!fLinesDecoded) {
767 return SkCodec::kIncompleteInput;
768 }
769 const int lastRow = fLinesDecoded + fFirstRow - 1;
770 SkASSERT(lastRow <= fLastRow);
771
772 // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it
773 // may be too tricky/expensive to handle that correctly.
774 png_bytep srcRow = fInterlaceBuffer.get();
775 const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1;
776 void* dst = fDst;
777 for (int rowNum = fFirstRow; rowNum <= lastRow; rowNum += sampleY) {
778 this->applyXformRow(dst, srcRow);
779 dst = SkTAddOffset<void>(dst, fRowBytes);
780 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY);
781 }
782
783 if (fInterlacedComplete) {
784 return SkCodec::kSuccess;
785 }
786
787 if (rowsDecoded) {
788 *rowsDecoded = fLinesDecoded;
789 }
790 return SkCodec::kIncompleteInput;
791 }
792
793 void setUpInterlaceBuffer(int height) {
794 fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr());
795 fInterlaceBuffer.reset(fPng_rowbytes * height);
796 fInterlacedComplete = false;
797 }
798 };
799
800 #ifdef SK_GOOGLE3_PNG_HACK
801 bool SkPngCodec::rereadHeaderIfNecessary() {
802 if (!fNeedsToRereadHeader) {
803 return true;
804 }
805
806 // On the first call, we'll need to rewind ourselves. Future calls will
807 // have already rewound in rewindIfNecessary.
808 if (this->stream()->getPosition() > 0) {
809 this->stream()->rewind();
810 }
811
812 this->destroyReadStruct();
813 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
814 sk_error_fn, sk_warning_fn);
815 if (!png_ptr) {
816 return false;
817 }
818
819 // Only use the AutoCleanPng to delete png_ptr as necessary.
820 // (i.e. not for reading bounds etc.)
821 AutoCleanPng autoClean(png_ptr, nullptr, nullptr, nullptr);
822
823 png_infop info_ptr = png_create_info_struct(png_ptr);
824 if (info_ptr == nullptr) {
825 return false;
826 }
827
828 autoClean.setInfoPtr(info_ptr);
829
830 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
831 // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
832 // This needs to be installed before we read the png header. Android may store ninepatch
833 // chunks in the header.
834 if (fPngChunkReader.get()) {
835 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
836 png_set_read_user_chunk_fn(png_ptr, (png_voidp) fPngChunkReader.get(), sk_read_user_chunk);
837 }
838 #endif
839
840 fPng_ptr = png_ptr;
841 fInfo_ptr = info_ptr;
842 autoClean.releasePngPtrs();
843 fNeedsToRereadHeader = false;
844 return true;
845 }
846 #endif // SK_GOOGLE3_PNG_HACK
847
848 // Reads the header and initializes the output fields, if not NULL.
849 //
850 // @param stream Input data. Will be read to get enough information to properly
851 // setup the codec.
852 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
853 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
854 // expected to continue to own it for the lifetime of the png_ptr.
855 // @param outCodec Optional output variable. If non-NULL, will be set to a new
856 // SkPngCodec on success.
857 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new
858 // png_structp on success.
859 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new
860 // png_infop on success;
861 // @return true on success, in which case the caller is responsible for calling
862 // png_destroy_read_struct(png_ptrp, info_ptrp).
863 // If it returns false, the passed in fields (except stream) are unchanged.
864 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec** outCodec,
865 png_structp* png_ptrp, png_infop* info_ptrp) {
866 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
867 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
868 sk_error_fn, sk_warning_fn);
869 if (!png_ptr) {
870 return false;
871 }
872
873 AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec);
874
875 png_infop info_ptr = png_create_info_struct(png_ptr);
876 if (info_ptr == nullptr) {
877 return false;
878 }
879
880 autoClean.setInfoPtr(info_ptr);
881
882 // FIXME: Could we use the return value of setjmp to specify the type of
883 // error?
884 if (setjmp(PNG_JMPBUF(png_ptr))) {
885 return false;
886 }
887
888 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
889 // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
890 // This needs to be installed before we read the png header. Android may store ninepatch
891 // chunks in the header.
892 if (chunkReader) {
893 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
894 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
895 }
896 #endif
897
898 const bool decodedBounds = autoClean.decodeBounds();
899
900 if (!decodedBounds) {
901 return false;
902 }
903
904 // On success, decodeBounds releases ownership of png_ptr and info_ptr.
905 if (png_ptrp) {
906 *png_ptrp = png_ptr;
907 }
908 if (info_ptrp) {
909 *info_ptrp = info_ptr;
910 }
911
912 // decodeBounds takes care of setting outCodec
913 if (outCodec) {
914 SkASSERT(*outCodec);
915 }
916 return true;
917 }
918
919 // FIXME (scroggo): Once SK_GOOGLE3_PNG_HACK is no more, this method can be inline in
920 // AutoCleanPng::infoCallback
921 static void general_info_callback(png_structp png_ptr, png_infop info_ptr,
922 SkEncodedInfo::Color* outColor, SkEncodedInfo::Alpha* outAlpha) {
923 png_uint_32 origWidth, origHeight;
924 int bitDepth, encodedColorType;
925 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
926 &encodedColorType, nullptr, nullptr, nullptr);
927
928 // Tell libpng to strip 16 bit/color files down to 8 bits/color.
929 // TODO: Should we handle this in SkSwizzler? Could this also benefit
930 // RAW decodes?
931 if (bitDepth == 16) {
932 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
933 png_set_strip_16(png_ptr);
934 }
935
936 // Now determine the default colorType and alphaType and set the required transforms.
937 // Often, we depend on SkSwizzler to perform any transforms that we need. However, we
938 // still depend on libpng for many of the rare and PNG-specific cases.
939 SkEncodedInfo::Color color;
940 SkEncodedInfo::Alpha alpha;
941 switch (encodedColorType) {
942 case PNG_COLOR_TYPE_PALETTE:
943 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
944 // byte into separate bytes (useful for paletted and grayscale images).
945 if (bitDepth < 8) {
946 // TODO: Should we use SkSwizzler here?
947 png_set_packing(png_ptr);
948 }
949
950 color = SkEncodedInfo::kPalette_Color;
951 // Set the alpha depending on if a transparency chunk exists.
952 alpha = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
953 SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha;
954 break;
955 case PNG_COLOR_TYPE_RGB:
956 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
957 // Convert to RGBA if transparency chunk exists.
958 png_set_tRNS_to_alpha(png_ptr);
959 color = SkEncodedInfo::kRGBA_Color;
960 alpha = SkEncodedInfo::kBinary_Alpha;
961 } else {
962 color = SkEncodedInfo::kRGB_Color;
963 alpha = SkEncodedInfo::kOpaque_Alpha;
964 }
965 break;
966 case PNG_COLOR_TYPE_GRAY:
967 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
968 if (bitDepth < 8) {
969 // TODO: Should we use SkSwizzler here?
970 png_set_expand_gray_1_2_4_to_8(png_ptr);
971 }
972
973 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
974 png_set_tRNS_to_alpha(png_ptr);
975 color = SkEncodedInfo::kGrayAlpha_Color;
976 alpha = SkEncodedInfo::kBinary_Alpha;
977 } else {
978 color = SkEncodedInfo::kGray_Color;
979 alpha = SkEncodedInfo::kOpaque_Alpha;
980 }
981 break;
982 case PNG_COLOR_TYPE_GRAY_ALPHA:
983 color = SkEncodedInfo::kGrayAlpha_Color;
984 alpha = SkEncodedInfo::kUnpremul_Alpha;
985 break;
986 case PNG_COLOR_TYPE_RGBA:
987 color = SkEncodedInfo::kRGBA_Color;
988 alpha = SkEncodedInfo::kUnpremul_Alpha;
989 break;
990 default:
991 // All the color types have been covered above.
992 SkASSERT(false);
993 color = SkEncodedInfo::kRGBA_Color;
994 alpha = SkEncodedInfo::kUnpremul_Alpha;
995 }
996 if (outColor) {
997 *outColor = color;
998 }
999 if (outAlpha) {
1000 *outAlpha = alpha;
1001 }
1002 }
1003
1004 #ifdef SK_GOOGLE3_PNG_HACK
1005 void SkPngCodec::rereadInfoCallback() {
1006 general_info_callback(fPng_ptr, fInfo_ptr, nullptr, nullptr);
1007 png_set_interlace_handling(fPng_ptr);
1008 png_read_update_info(fPng_ptr, fInfo_ptr);
1009 }
1010 #endif
1011
1012 void AutoCleanPng::infoCallback() {
1013 SkEncodedInfo::Color color;
1014 SkEncodedInfo::Alpha alpha;
1015 general_info_callback(fPng_ptr, fInfo_ptr, &color, &alpha);
1016
1017 const int numberPasses = png_set_interlace_handling(fPng_ptr);
1018
1019 fReadHeader = true;
1020 fDecodedBounds = true;
1021 #ifndef SK_GOOGLE3_PNG_HACK
1022 // 1 tells libpng to save any extra data. We may be able to be more efficient by saving
1023 // it ourselves.
1024 png_process_data_pause(fPng_ptr, 1);
1025 #else
1026 // Hack to make png_process_data stop.
1027 fPng_ptr->buffer_size = 0;
1028 #endif
1029 if (fOutCodec) {
1030 SkASSERT(nullptr == *fOutCodec);
1031 sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr);
1032 if (!colorSpace) {
1033 // Treat unmarked pngs as sRGB.
1034 colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
1035 }
1036
1037 SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, 8);
1038 // FIXME (scroggo): Once we get rid of SK_GOOGLE3_PNG_HACK, general_info_callback can
1039 // be inlined, so these values will already be set.
1040 png_uint_32 origWidth = png_get_image_width(fPng_ptr, fInfo_ptr);
1041 png_uint_32 origHeight = png_get_image_height(fPng_ptr, fInfo_ptr);
1042 png_byte bitDepth = png_get_bit_depth(fPng_ptr, fInfo_ptr);
1043 SkImageInfo imageInfo = encodedInfo.makeImageInfo(origWidth, origHeight, colorSpace);
1044
1045 if (SkEncodedInfo::kOpaque_Alpha == alpha) {
1046 png_color_8p sigBits;
1047 if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
1048 if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
1049 // Recommend a decode to 565 if the sBIT indicates 565.
1050 imageInfo = imageInfo.makeColorType(kRGB_565_SkColorType);
1051 }
1052 }
1053 }
1054
1055 if (1 == numberPasses) {
1056 *fOutCodec = new SkPngNormalDecoder(encodedInfo, imageInfo, fStream,
1057 fChunkReader, fPng_ptr, fInfo_ptr, bitDepth);
1058 } else {
1059 *fOutCodec = new SkPngInterlacedDecoder(encodedInfo, imageInfo, fStream,
1060 fChunkReader, fPng_ptr, fInfo_ptr, bitDepth, numberPasses);
1061 }
1062 }
1063
1064
1065 // Release the pointers, which are now owned by the codec or the caller is expected to
1066 // take ownership.
1067 this->releasePngPtrs();
1068 }
1069
1070 SkPngCodec::SkPngCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
1071 SkStream* stream, SkPngChunkReader* chunkReader, void* png_ptr,
1072 void* info_ptr, int bitDepth)
1073 : INHERITED(encodedInfo, imageInfo, stream)
1074 , fPngChunkReader(SkSafeRef(chunkReader))
1075 , fPng_ptr(png_ptr)
1076 , fInfo_ptr(info_ptr)
1077 , fColorXformSrcRow(nullptr)
1078 , fBitDepth(bitDepth)
1079 #ifdef SK_GOOGLE3_PNG_HACK
1080 , fNeedsToRereadHeader(true)
1081 #endif
1082 {}
1083
1084 SkPngCodec::~SkPngCodec() {
1085 this->destroyReadStruct();
1086 }
1087
1088 void SkPngCodec::destroyReadStruct() {
1089 if (fPng_ptr) {
1090 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
1091 SkASSERT(fInfo_ptr);
1092 png_destroy_read_struct((png_struct**)&fPng_ptr, (png_info**)&fInfo_ptr, nullptr);
1093 fPng_ptr = nullptr;
1094 fInfo_ptr = nullptr;
1095 }
1096 }
1097
1098 ///////////////////////////////////////////////////////////////////////////////
1099 // Getting the pixels
1100 ///////////////////////////////////////////////////////////////////////////////
1101
1102 bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options,
1103 SkPMColor ctable[], int* ctableCount) {
1104 if (setjmp(PNG_JMPBUF((png_struct*)fPng_ptr))) {
1105 SkCodecPrintf("Failed on png_read_update_info.\n");
1106 return false;
1107 }
1108 png_read_update_info(fPng_ptr, fInfo_ptr);
1109
1110 // Reset fSwizzler and fColorXform. We can't do this in onRewind() because the
1111 // interlaced scanline decoder may need to rewind.
1112 fSwizzler.reset(nullptr);
1113 fColorXform = nullptr;
1114
1115 if (needs_color_xform(dstInfo, this->getInfo())) {
1116 fColorXform = SkColorSpaceXform::New(this->getInfo().colorSpace(), dstInfo.colorSpace());
1117 SkASSERT(fColorXform);
1118 }
1119
1120 // If the image is RGBA and we have a color xform, we can skip the swizzler.
1121 // FIXME (msarett):
1122 // Support more input types to fColorXform (ex: RGB, Gray) and skip the swizzler more often.
1123 if (fColorXform && SkEncodedInfo::kRGBA_Color == this->getEncodedInfo().color() &&
1124 !options.fSubset)
1125 {
1126 fXformMode = kColorOnly_XformMode;
1127 return true;
1128 }
1129
1130 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
1131 if (!this->createColorTable(dstInfo, ctableCount)) {
1132 return false;
1133 }
1134 }
1135
1136 // Copy the color table to the client if they request kIndex8 mode.
1137 copy_color_table(dstInfo, fColorTable, ctable, ctableCount);
1138
1139 this->initializeSwizzler(dstInfo, options);
1140 return true;
1141 }
1142
1143 void SkPngCodec::initializeXformParams() {
1144 switch (fXformMode) {
1145 case kColorOnly_XformMode:
1146 fXformColorFormat = select_xform_format(this->dstInfo().colorType());
1147 fXformAlphaType = select_xform_alpha(this->dstInfo().alphaType(),
1148 this->getInfo().alphaType());
1149 fXformWidth = this->dstInfo().width();
1150 break;
1151 case kSwizzleColor_XformMode:
1152 fXformColorFormat = select_xform_format(this->dstInfo().colorType());
1153 fXformAlphaType = select_xform_alpha(this->dstInfo().alphaType(),
1154 this->getInfo().alphaType());
1155 fXformWidth = this->swizzler()->swizzleWidth();
1156 break;
1157 default:
1158 break;
1159 }
1160 }
1161
1162 static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) {
1163 // We will apply the color xform when reading the color table, unless F16 is requested.
1164 return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
1165 }
1166
1167 void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
1168 SkImageInfo swizzlerInfo = dstInfo;
1169 Options swizzlerOptions = options;
1170 fXformMode = kSwizzleOnly_XformMode;
1171 if (fColorXform && apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color())) {
1172 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
1173 if (kPremul_SkAlphaType == dstInfo.alphaType()) {
1174 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
1175 }
1176
1177 fXformMode = kSwizzleColor_XformMode;
1178
1179 // Here, we swizzle into temporary memory, which is not zero initialized.
1180 // FIXME (msarett):
1181 // Is this a problem?
1182 swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized;
1183 }
1184
1185 const SkPMColor* colors = get_color_ptr(fColorTable.get());
1186 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, swizzlerInfo,
1187 swizzlerOptions));
1188 SkASSERT(fSwizzler);
1189 }
1190
1191 SkSampler* SkPngCodec::getSampler(bool createIfNecessary) {
1192 if (fSwizzler || !createIfNecessary) {
1193 return fSwizzler;
1194 }
1195
1196 this->initializeSwizzler(this->dstInfo(), this->options());
1197 return fSwizzler;
1198 }
1199
1200 bool SkPngCodec::onRewind() {
1201 #ifdef SK_GOOGLE3_PNG_HACK
1202 fNeedsToRereadHeader = true;
1203 return true;
1204 #else
1205 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
1206 // succeeds, they will be repopulated, and if it fails, they will
1207 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
1208 // come through this function which will rewind and again attempt
1209 // to reinitialize them.
1210 this->destroyReadStruct();
1211
1212 png_structp png_ptr;
1213 png_infop info_ptr;
1214 if (!read_header(this->stream(), fPngChunkReader.get(), nullptr, &png_ptr, &info_ptr)) {
1215 return false;
1216 }
1217
1218 fPng_ptr = png_ptr;
1219 fInfo_ptr = info_ptr;
1220 return true;
1221 #endif
1222 }
1223
1224 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
1225 size_t rowBytes, const Options& options,
1226 SkPMColor ctable[], int* ctableCount,
1227 int* rowsDecoded) {
1228 if (!conversion_possible(dstInfo, this->getInfo()) ||
1229 !this->initializeXforms(dstInfo, options, ctable, ctableCount))
1230 {
1231 return kInvalidConversion;
1232 }
1233 #ifdef SK_GOOGLE3_PNG_HACK
1234 // Note that this is done after initializeXforms. Otherwise that method
1235 // would not have png_ptr to use.
1236 if (!this->rereadHeaderIfNecessary()) {
1237 return kCouldNotRewind;
1238 }
1239 #endif
1240
1241 if (options.fSubset) {
1242 return kUnimplemented;
1243 }
1244
1245 this->allocateStorage(dstInfo);
1246 this->initializeXformParams();
1247 return this->decodeAllRows(dst, rowBytes, rowsDecoded);
1248 }
1249
1250 SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
1251 void* dst, size_t rowBytes, const SkCodec::Options& options,
1252 SkPMColor* ctable, int* ctableCount) {
1253 if (!conversion_possible(dstInfo, this->getInfo()) ||
1254 !this->initializeXforms(dstInfo, options, ctable, ctableCount))
1255 {
1256 return kInvalidConversion;
1257 }
1258 #ifdef SK_GOOGLE3_PNG_HACK
1259 // See note in onGetPixels.
1260 if (!this->rereadHeaderIfNecessary()) {
1261 return kCouldNotRewind;
1262 }
1263 #endif
1264
1265 this->allocateStorage(dstInfo);
1266
1267 int firstRow, lastRow;
1268 if (options.fSubset) {
1269 firstRow = options.fSubset->top();
1270 lastRow = options.fSubset->bottom() - 1;
1271 } else {
1272 firstRow = 0;
1273 lastRow = dstInfo.height() - 1;
1274 }
1275 this->setRange(firstRow, lastRow, dst, rowBytes);
1276 return kSuccess;
1277 }
1278
1279 SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) {
1280 // FIXME: Only necessary on the first call.
1281 this->initializeXformParams();
1282
1283 return this->decode(rowsDecoded);
1284 }
1285
1286 uint64_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const {
1287 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
1288 if (colorPtr) {
1289 SkAlphaType alphaType = select_xform_alpha(dstInfo.alphaType(),
1290 this->getInfo().alphaType());
1291 return get_color_table_fill_value(dstInfo.colorType(), alphaType, colorPtr, 0,
1292 fColorXform.get());
1293 }
1294 return INHERITED::onGetFillValue(dstInfo);
1295 }
1296
1297 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
1298 SkAutoTDelete<SkStream> streamDeleter(stream);
1299
1300 SkCodec* outCodec = nullptr;
1301 if (read_header(streamDeleter.get(), chunkReader, &outCodec, nullptr, nullptr)) {
1302 // Codec has taken ownership of the stream.
1303 SkASSERT(outCodec);
1304 streamDeleter.release();
1305 return outCodec;
1306 }
1307
1308 return nullptr;
1309 }
1310