Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: src/codec/SkPngCodec.cpp

Issue 2023103002: Revert of Make SkPngCodec decode progressively. (Closed) Base URL: https://skia.googlesource.com/skia.git@foil
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkPngCodec.h ('k') | src/codec/SkSampledCodec.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBitmap.h" 8 #include "SkBitmap.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
11 #include "SkColorSpace.h" 11 #include "SkColorSpace.h"
12 #include "SkColorTable.h" 12 #include "SkColorTable.h"
13 #include "SkMath.h" 13 #include "SkMath.h"
14 #include "SkOpts.h" 14 #include "SkOpts.h"
15 #include "SkPngCodec.h" 15 #include "SkPngCodec.h"
16 #include "SkSize.h" 16 #include "SkSize.h"
17 #include "SkStream.h" 17 #include "SkStream.h"
18 #include "SkSwizzler.h" 18 #include "SkSwizzler.h"
19 #include "SkTemplates.h" 19 #include "SkTemplates.h"
20 #include "SkUtils.h" 20 #include "SkUtils.h"
21 21
22 #ifdef SK_HAS_PNG_LIBRARY
23 /////////////////////////////////////////////////////////////////////////////// 22 ///////////////////////////////////////////////////////////////////////////////
24 // Callback functions 23 // Callback functions
25 /////////////////////////////////////////////////////////////////////////////// 24 ///////////////////////////////////////////////////////////////////////////////
26 25
27 // When setjmp is first called, it returns 0, meaning longjmp was not called.
28 constexpr int kSetJmpOkay = 0;
29 // An error internal to libpng.
30 constexpr int kPngError = 1;
31 // Passed to longjmp when we have decoded as many lines as we need.
32 constexpr int kStopDecoding = 2;
33
34 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 26 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
35 SkCodecPrintf("------ png error %s\n", msg); 27 SkCodecPrintf("------ png error %s\n", msg);
36 longjmp(png_jmpbuf(png_ptr), kPngError); 28 longjmp(png_jmpbuf(png_ptr), 1);
37 } 29 }
38 30
39 void sk_warning_fn(png_structp, png_const_charp msg) { 31 void sk_warning_fn(png_structp, png_const_charp msg) {
40 SkCodecPrintf("----- png warning %s\n", msg); 32 SkCodecPrintf("----- png warning %s\n", msg);
41 } 33 }
42 34
35 static void sk_read_fn(png_structp png_ptr, png_bytep data,
36 png_size_t length) {
37 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr));
38 const size_t bytes = stream->read(data, length);
39 if (bytes != length) {
40 // FIXME: We want to report the fact that the stream was truncated.
41 // One way to do that might be to pass a enum to longjmp so setjmp can
42 // specify the failure.
43 png_error(png_ptr, "Read Error!");
44 }
45 }
46
43 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 47 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
44 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 48 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
45 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(pn g_ptr); 49 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(pn g_ptr);
46 // readChunk() returning true means continue decoding 50 // readChunk() returning true means continue decoding
47 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk-> size) ? 1 : -1; 51 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk-> size) ? 1 : -1;
48 } 52 }
49 #endif 53 #endif
50 54
51 /////////////////////////////////////////////////////////////////////////////// 55 ///////////////////////////////////////////////////////////////////////////////
52 // Helpers 56 // Helpers
53 /////////////////////////////////////////////////////////////////////////////// 57 ///////////////////////////////////////////////////////////////////////////////
54 58
55 class AutoCleanPng : public SkNoncopyable { 59 class AutoCleanPng : public SkNoncopyable {
56 public: 60 public:
57 /* 61 AutoCleanPng(png_structp png_ptr)
58 * This class does not take ownership of stream or reader, but if codecPtr
59 * is non-NULL, and decodeBounds succeeds, it will have created a new
60 * SkCodec (pointed to by *codecPtr) which will own/ref them, as well as
61 * the png_ptr and info_ptr.
62 */
63 AutoCleanPng(png_structp png_ptr, SkStream* stream, SkPngChunkReader* reader ,
64 SkCodec** codecPtr)
65 : fPng_ptr(png_ptr) 62 : fPng_ptr(png_ptr)
66 , fInfo_ptr(nullptr) 63 , fInfo_ptr(nullptr) {}
67 , fDecodedBounds(false)
68 , fStream(stream)
69 , fChunkReader(reader)
70 , fOutCodec(codecPtr)
71 {}
72 64
73 ~AutoCleanPng() { 65 ~AutoCleanPng() {
74 // fInfo_ptr will never be non-nullptr unless fPng_ptr is. 66 // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
75 if (fPng_ptr) { 67 if (fPng_ptr) {
76 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr; 68 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
77 png_destroy_read_struct(&fPng_ptr, info_pp, nullptr); 69 png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
78 } 70 }
79 } 71 }
80 72
81 void setInfoPtr(png_infop info_ptr) { 73 void setInfoPtr(png_infop info_ptr) {
82 SkASSERT(nullptr == fInfo_ptr); 74 SkASSERT(nullptr == fInfo_ptr);
83 fInfo_ptr = info_ptr; 75 fInfo_ptr = info_ptr;
84 } 76 }
85 77
86 /** 78 void release() {
87 * Reads enough of the input stream to decode the bounds.
88 * @return false if the stream is not a valid PNG (or too short).
89 * true if it read enough of the stream to determine the bounds.
90 * In the latter case, the stream may have been read beyond the
91 * point to determine the bounds, and the png_ptr will have saved
92 * any extra data. Further, if the codecPtr supplied to the
93 * constructor was not NULL, it will now point to a new SkCodec,
94 * which owns (or refs, in the case of the SkPngChunkReader) the
95 * inputs. If codecPtr was NULL, the png_ptr and info_ptr are
96 * unowned, and it is up to the caller to destroy them.
97 */
98 bool decodeBounds();
99
100 private:
101 png_structp fPng_ptr;
102 png_infop fInfo_ptr;
103 bool fDecodedBounds;
104 SkStream* fStream;
105 SkPngChunkReader* fChunkReader;
106 SkCodec** fOutCodec;
107
108 /**
109 * Supplied to libpng to call when it has read enough data to determine
110 * bounds.
111 */
112 static void InfoCallback(png_structp png_ptr, png_infop info_ptr) {
113 // png_get_progressive_ptr returns the pointer we set on the png_ptr wit h
114 // png_set_progressive_read_fn
115 static_cast<AutoCleanPng*>(png_get_progressive_ptr(png_ptr))->infoCallba ck();
116 }
117
118 void infoCallback();
119
120 void releasePngPtrs() {
121 fPng_ptr = nullptr; 79 fPng_ptr = nullptr;
122 fInfo_ptr = nullptr; 80 fInfo_ptr = nullptr;
123 } 81 }
82
83 private:
84 png_structp fPng_ptr;
85 png_infop fInfo_ptr;
124 }; 86 };
125 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) 87 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
126 88
127 bool AutoCleanPng::decodeBounds() {
128 if (setjmp(png_jmpbuf(fPng_ptr))) {
129 return false;
130 }
131
132 png_set_progressive_read_fn(fPng_ptr, this, InfoCallback, nullptr, nullptr);
133
134 // Arbitrary buffer size, though note that it matches (below)
135 // SkPngCodec::processData(). FIXME: Can we better suit this to the size of
136 // the PNG header?
137 constexpr size_t kBufferSize = 4096;
138 char buffer[kBufferSize];
139
140 while (true) {
141 const size_t bytesRead = fStream->read(buffer, kBufferSize);
142 if (!bytesRead) {
143 // We have read to the end of the input without decoding bounds.
144 break;
145 }
146
147 png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, bytesRead);
148 if (fDecodedBounds) {
149 break;
150 }
151 }
152
153 // For safety, clear the pointer to this object.
154 png_set_progressive_read_fn(fPng_ptr, nullptr, nullptr, nullptr, nullptr);
155 return fDecodedBounds;
156 }
157
158 void SkPngCodec::processData() {
159 switch (setjmp(png_jmpbuf(fPng_ptr))) {
160 case kPngError:
161 // There was an error. Stop processing data.
162 // FIXME: Do we need to discard png_ptr?
163 return;
164 case kStopDecoding:
165 // We decoded all the lines we want.
166 return;
167 case kSetJmpOkay:
168 // Everything is okay.
169 break;
170 default:
171 // No other values should be passed to longjmp.
172 SkASSERT(false);
173 }
174
175 // Arbitrary buffer size
176 constexpr size_t kBufferSize = 4096;
177 char buffer[kBufferSize];
178
179 while (true) {
180 const size_t bytesRead = this->stream()->read(buffer, kBufferSize);
181 png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, bytesRead);
182
183 if (!bytesRead) {
184 // We have read to the end of the input. Note that we quit *after*
185 // calling png_process_data, because decodeBounds may have told
186 // libpng to save the remainder of the buffer, in which case
187 // png_process_data will process the saved buffer, though the
188 // stream has no more to read.
189 break;
190 }
191 }
192 }
193
194 // Note: SkColorTable claims to store SkPMColors, which is not necessarily 89 // Note: SkColorTable claims to store SkPMColors, which is not necessarily
195 // the case here. 90 // the case here.
91 // TODO: If we add support for non-native swizzles, we'll need to handle that he re.
196 bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, in t* ctableCount) { 92 bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, in t* ctableCount) {
197 93
198 int numColors; 94 int numColors;
199 png_color* palette; 95 png_color* palette;
200 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { 96 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
201 return false; 97 return false;
202 } 98 }
203 99
204 // Note: These are not necessarily SkPMColors. 100 // Note: These are not necessarily SkPMColors.
205 SkPMColor colorPtr[256]; 101 SkPMColor colorPtr[256];
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 260
365 #endif // LIBPNG >= 1.6 261 #endif // LIBPNG >= 1.6
366 262
367 // Finally, what should we do if there is no color space information in the PNG? 263 // Finally, what should we do if there is no color space information in the PNG?
368 // The specification says that this indicates "gamma is unknown" and that th e 264 // The specification says that this indicates "gamma is unknown" and that th e
369 // "color is device dependent". I'm assuming we can represent this with NUL L. 265 // "color is device dependent". I'm assuming we can represent this with NUL L.
370 // But should we guess sRGB? Most images are sRGB, even if they don't speci fy. 266 // But should we guess sRGB? Most images are sRGB, even if they don't speci fy.
371 return nullptr; 267 return nullptr;
372 } 268 }
373 269
374 class SkPngNormalDecoder : public SkPngCodec { 270 static int bytes_per_pixel(int bitsPerPixel) {
271 // Note that we will have to change this implementation if we start
272 // supporting outputs from libpng that are less than 8-bits per component.
273 return bitsPerPixel / 8;
274 }
275
276 // Subclass of SkPngCodec which supports scanline decoding
277 class SkPngScanlineDecoder : public SkPngCodec {
375 public: 278 public:
376 SkPngNormalDecoder(int width, int height, const SkEncodedInfo& info, SkStrea m* stream, 279 SkPngScanlineDecoder(int width, int height, const SkEncodedInfo& info, SkStr eam* stream,
377 SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, i nt bitDepth, 280 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth,
378 sk_sp<SkColorSpace> colorSpace) 281 sk_sp<SkColorSpace> colorSpace)
379 : INHERITED(width, height, info, stream, reader, png_ptr, info_ptr, bitD epth, 282 : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1,
380 std::move(colorSpace)) 283 colorSpace)
381 , fLinesDecoded(0) 284 , fSrcRow(nullptr)
382 , fDst(nullptr)
383 , fRowBytes(0)
384 , fFirstRow(0)
385 , fLastRow(0)
386 {} 285 {}
387 286
388 static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) { 287 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
389 GetDecoder(png_ptr)->allRowsCallback(row, rowNum); 288 SkPMColor ctable[], int* ctableCount) override {
390 } 289 if (!conversion_possible(dstInfo, this->getInfo())) {
391 290 return kInvalidConversion;
392 static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowN um, int /*pass*/) { 291 }
393 GetDecoder(png_ptr)->rowCallback(row, rowNum); 292
394 } 293 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
294 ctableCount);
295 if (result != kSuccess) {
296 return result;
297 }
298
299 fStorage.reset(this->getInfo().width() *
300 (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel())));
301 fSrcRow = fStorage.get();
302
303 return kSuccess;
304 }
305
306 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
307 // Assume that an error in libpng indicates an incomplete input.
308 int row = 0;
309 if (setjmp(png_jmpbuf(this->png_ptr()))) {
310 SkCodecPrintf("setjmp long jump!\n");
311 return row;
312 }
313
314 void* dstRow = dst;
315 for (; row < count; row++) {
316 png_read_row(this->png_ptr(), fSrcRow, nullptr);
317 this->swizzler()->swizzle(dstRow, fSrcRow);
318 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
319 }
320
321 return row;
322 }
323
324 bool onSkipScanlines(int count) override {
325 // Assume that an error in libpng indicates an incomplete input.
326 if (setjmp(png_jmpbuf(this->png_ptr()))) {
327 SkCodecPrintf("setjmp long jump!\n");
328 return false;
329 }
330
331 for (int row = 0; row < count; row++) {
332 png_read_row(this->png_ptr(), fSrcRow, nullptr);
333 }
334 return true;
335 }
336
395 private: 337 private:
396 int fLinesDecoded; // FIXME: Move to baseclass? 338 SkAutoTMalloc<uint8_t> fStorage;
397 void* fDst; 339 uint8_t* fSrcRow;
398 size_t fRowBytes;
399
400 // Variables for partial decode
401 int fFirstRow; // FIXME: Move to baseclass?
402 int fLastRow;
403 340
404 typedef SkPngCodec INHERITED; 341 typedef SkPngCodec INHERITED;
405
406 static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) {
407 return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr) );
408 }
409
410 Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
411 const int height = this->getInfo().height();
412 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, AllRowsCallb ack, nullptr);
413 fDst = dst;
414 fRowBytes = rowBytes;
415
416 fLinesDecoded = 0;
417
418 this->processData();
419
420 if (fLinesDecoded == height) {
421 return SkCodec::kSuccess;
422 }
423
424 if (rowsDecoded) {
425 *rowsDecoded = fLinesDecoded;
426 }
427
428 return SkCodec::kIncompleteInput;
429 }
430
431 void allRowsCallback(png_bytep row, int rowNum) {
432 SkASSERT(rowNum - fFirstRow == fLinesDecoded);
433 fLinesDecoded++;
434 this->swizzler()->swizzle(fDst, row);
435 fDst = SkTAddOffset<void>(fDst, fRowBytes);
436 }
437
438 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) overrid e {
439 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, RowCallback, nullptr);
440 fFirstRow = firstRow;
441 fLastRow = lastRow;
442 fDst = dst;
443 fRowBytes = rowBytes;
444 fLinesDecoded = 0;
445 }
446
447 SkCodec::Result decode(int* rowsDecoded) override {
448 this->processData();
449
450 if (fLinesDecoded == fLastRow - fFirstRow + 1) {
451 return SkCodec::kSuccess;
452 }
453
454 if (rowsDecoded) {
455 *rowsDecoded = fLinesDecoded;
456 }
457
458 return SkCodec::kIncompleteInput;
459 }
460
461 void rowCallback(png_bytep row, int rowNum) {
462 if (rowNum < fFirstRow) {
463 // Ignore this row.
464 return;
465 }
466
467 SkASSERT(rowNum <= fLastRow);
468
469 if (this->swizzler()->rowNeeded(fLinesDecoded)) {
470 this->swizzler()->swizzle(fDst, row);
471 fDst = SkTAddOffset<void>(fDst, fRowBytes);
472 }
473
474 fLinesDecoded++;
475
476 if (rowNum == fLastRow) {
477 // Fake error to stop decoding scanlines.
478 longjmp(png_jmpbuf(this->png_ptr()), kStopDecoding);
479 }
480 }
481 }; 342 };
482 343
483 class SkPngInterlacedDecoder : public SkPngCodec { 344
345 class SkPngInterlacedScanlineDecoder : public SkPngCodec {
484 public: 346 public:
485 SkPngInterlacedDecoder(int width, int height, const SkEncodedInfo& info, SkS tream* stream, 347 SkPngInterlacedScanlineDecoder(int width, int height, const SkEncodedInfo& i nfo,
486 SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, i nt bitDepth, 348 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr ,
487 sk_sp<SkColorSpace> colorSpace, int numberPasses) 349 png_infop info_ptr, int bitDepth, int numberPasses, sk_sp<SkColorSpa ce> colorSpace)
488 : INHERITED(width, height, info, stream, reader, png_ptr, info_ptr, bitD epth, 350 : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth,
489 std::move(colorSpace)) 351 numberPasses, colorSpace)
490 , fNumberPasses(numberPasses) 352 , fHeight(-1)
491 , fFirstRow(0) 353 , fCanSkipRewind(false)
492 , fLastRow(0) 354 {
493 , fLinesDecoded(0) 355 SkASSERT(numberPasses != 1);
494 , fInterlacedComplete(false) 356 }
495 , fPng_rowbytes(0) 357
496 {} 358 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
497 359 SkPMColor ctable[], int* ctableCount) override {
498 static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_ui nt_32 rowNum, int pass) { 360 if (!conversion_possible(dstInfo, this->getInfo())) {
499 auto decoder = static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ ptr(png_ptr)); 361 return kInvalidConversion;
500 decoder->interlacedRowCallback(row, rowNum, pass); 362 }
363
364 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
365 ctableCount);
366 if (result != kSuccess) {
367 return result;
368 }
369
370 fHeight = dstInfo.height();
371 // FIXME: This need not be called on a second call to onStartScanlineDec ode.
372 fSrcRowBytes = this->getInfo().width() *
373 (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel()));
374 fGarbageRow.reset(fSrcRowBytes);
375 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
376 fCanSkipRewind = true;
377
378 return SkCodec::kSuccess;
379 }
380
381 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
382 // rewind stream if have previously called onGetScanlines,
383 // since we need entire progressive image to get scanlines
384 if (fCanSkipRewind) {
385 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind.
386 // Next time onGetScanlines is called, we will need to rewind.
387 fCanSkipRewind = false;
388 } else {
389 // rewindIfNeeded resets fCurrScanline, since it assumes that start
390 // needs to be called again before scanline decoding. PNG scanline
391 // decoding is the exception, since it needs to rewind between
392 // calls to getScanlines. Keep track of fCurrScanline, to undo the
393 // reset.
394 const int currScanline = this->nextScanline();
395 // This method would never be called if currScanline is -1
396 SkASSERT(currScanline != -1);
397
398 if (!this->rewindIfNeeded()) {
399 return kCouldNotRewind;
400 }
401 this->updateCurrScanline(currScanline);
402 }
403
404 if (setjmp(png_jmpbuf(this->png_ptr()))) {
405 SkCodecPrintf("setjmp long jump!\n");
406 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
407 // we may be able to report that all of the memory has been initiali zed. Even if we
408 // fail on the first pass, we can still report than some scanlines a re initialized.
409 return 0;
410 }
411 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
412 uint8_t* storagePtr = storage.get();
413 uint8_t* srcRow;
414 const int startRow = this->nextScanline();
415 for (int i = 0; i < this->numberPasses(); i++) {
416 // read rows we planned to skip into garbage row
417 for (int y = 0; y < startRow; y++){
418 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
419 }
420 // read rows we care about into buffer
421 srcRow = storagePtr;
422 for (int y = 0; y < count; y++) {
423 png_read_row(this->png_ptr(), srcRow, nullptr);
424 srcRow += fSrcRowBytes;
425 }
426 // read rows we don't want into garbage buffer
427 for (int y = 0; y < fHeight - startRow - count; y++) {
428 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
429 }
430 }
431 //swizzle the rows we care about
432 srcRow = storagePtr;
433 void* dstRow = dst;
434 for (int y = 0; y < count; y++) {
435 this->swizzler()->swizzle(dstRow, srcRow);
436 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
437 srcRow += fSrcRowBytes;
438 }
439
440 return count;
441 }
442
443 bool onSkipScanlines(int count) override {
444 // The non-virtual version will update fCurrScanline.
445 return true;
446 }
447
448 SkScanlineOrder onGetScanlineOrder() const override {
449 return kNone_SkScanlineOrder;
501 } 450 }
502 451
503 private: 452 private:
504 const int fNumberPasses; 453 int fHeight;
505 int fFirstRow; 454 size_t fSrcRowBytes;
506 int fLastRow; 455 SkAutoMalloc fGarbageRow;
507 void* fDst; 456 uint8_t* fGarbageRowPtr;
508 size_t fRowBytes; 457 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
509 int fLinesDecoded; 458 // is called whenever some action is taken that reads the stream and
510 bool fInterlacedComplete; 459 // therefore the next call will require a rewind. So it modifies a boolean
511 size_t fPng_rowbytes; 460 // to note that the *next* time it is called a rewind is needed.
512 SkAutoTMalloc<png_byte> fInterlaceBuffer; 461 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
462 // onStartScanlineDecode followed by onGetScanlines does *not* require a
463 // rewind. Since rewindIfNeeded does not have this flexibility, we need to
464 // add another layer.
465 bool fCanSkipRewind;
513 466
514 typedef SkPngCodec INHERITED; 467 typedef SkPngCodec INHERITED;
515
516 // FIXME: Currently sharing interlaced callback for all rows and subset. It' s not
517 // as expensive as the subset version of non-interlaced, but it still does e xtra
518 // work.
519 void interlacedRowCallback(png_bytep row, int rowNum, int pass) {
520 if (rowNum < fFirstRow || rowNum > fLastRow) {
521 // Ignore this row
522 return;
523 }
524
525 png_bytep oldRow = fInterlaceBuffer.get() + (rowNum - fFirstRow) * fPng_ rowbytes;
526 png_progressive_combine_row(this->png_ptr(), oldRow, row);
527
528 if (0 == pass) {
529 // The first pass initializes all rows.
530 SkASSERT(row);
531 SkASSERT(fLinesDecoded == rowNum - fFirstRow);
532 fLinesDecoded++;
533 } else {
534 SkASSERT(fLinesDecoded == fLastRow - fFirstRow + 1);
535 if (fNumberPasses - 1 == pass && rowNum == fLastRow) {
536 // Last pass, and we have read all of the rows we care about. No te that
537 // we do not care about reading anything beyond the end of the i mage (or
538 // beyond the last scanline requested).
539 fInterlacedComplete = true;
540 // Fake error to stop decoding scanlines.
541 longjmp(png_jmpbuf(this->png_ptr()), kStopDecoding);
542 }
543 }
544 }
545
546 SkCodec::Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
547 const int height = this->getInfo().height();
548 this->setUpInterlaceBuffer(height);
549 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRo wCallback, nullptr);
550
551 fFirstRow = 0;
552 fLastRow = height - 1;
553 fLinesDecoded = 0;
554
555 this->processData();
556
557 png_bytep srcRow = fInterlaceBuffer.get();
558 // FIXME: When resuming, this may rewrite rows that did not change.
559 for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) {
560 this->swizzler()->swizzle(dst, srcRow);
561 dst = SkTAddOffset<void>(dst, rowBytes);
562 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes);
563 }
564 if (fInterlacedComplete) {
565 return SkCodec::kSuccess;
566 }
567
568 if (rowsDecoded) {
569 *rowsDecoded = fLinesDecoded;
570 }
571
572 return SkCodec::kIncompleteInput;
573 }
574
575 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) overrid e {
576 // FIXME: We could skip rows in the interlace buffer that we won't put i n the output.
577 this->setUpInterlaceBuffer(lastRow - firstRow + 1);
578 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRo wCallback, nullptr);
579 fFirstRow = firstRow;
580 fLastRow = lastRow;
581 fDst = dst;
582 fRowBytes = rowBytes;
583 fLinesDecoded = 0;
584 }
585
586 SkCodec::Result decode(int* rowsDecoded) override {
587 this->processData();
588
589 // Now call the callback on all the rows that were decoded.
590 if (!fLinesDecoded) {
591 return SkCodec::kIncompleteInput;
592 }
593 const int lastRow = fLinesDecoded + fFirstRow - 1;
594 SkASSERT(lastRow <= fLastRow);
595
596 // FIXME: For resuming interlace, we may swizzle a row that hasn't chang ed. But it
597 // may be too tricky/expensive to handle that correctly.
598 png_bytep srcRow = fInterlaceBuffer.get();
599 const int sampleY = this->swizzler()->sampleY();
600 void* dst = fDst;
601 for (int rowNum = fFirstRow; rowNum <= lastRow; rowNum += sampleY) {
602 this->swizzler()->swizzle(dst, srcRow);
603 dst = SkTAddOffset<void>(dst, fRowBytes);
604 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY);
605 }
606
607 if (fInterlacedComplete) {
608 return SkCodec::kSuccess;
609 }
610
611 if (rowsDecoded) {
612 *rowsDecoded = fLinesDecoded;
613 }
614 return SkCodec::kIncompleteInput;
615 }
616
617 void setUpInterlaceBuffer(int height) {
618 fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr());
619 fInterlaceBuffer.reset(fPng_rowbytes * height);
620 fInterlacedComplete = false;
621 }
622 }; 468 };
623 469
624 // Reads the header and initializes the output fields, if not NULL. 470 // Reads the header and initializes the output fields, if not NULL.
625 // 471 //
626 // @param stream Input data. Will be read to get enough information to properly 472 // @param stream Input data. Will be read to get enough information to properly
627 // setup the codec. 473 // setup the codec.
628 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. 474 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
629 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is 475 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
630 // expected to continue to own it for the lifetime of the png_ptr. 476 // expected to continue to own it for the lifetime of the png_ptr.
631 // @param outCodec Optional output variable. If non-NULL, will be set to a new 477 // @param outCodec Optional output variable. If non-NULL, will be set to a new
632 // SkPngCodec on success. 478 // SkPngCodec on success.
633 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new 479 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new
634 // png_structp on success. 480 // png_structp on success.
635 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new 481 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new
636 // png_infop on success; 482 // png_infop on success;
637 // @return true on success, in which case the caller is responsible for calling 483 // @return true on success, in which case the caller is responsible for calling
638 // png_destroy_read_struct(png_ptrp, info_ptrp). 484 // png_destroy_read_struct(png_ptrp, info_ptrp).
639 // If it returns false, the passed in fields (except stream) are unchanged. 485 // If it returns false, the passed in fields (except stream) are unchanged.
640 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec ** outCodec, 486 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec ** outCodec,
641 png_structp* png_ptrp, png_infop* info_ptrp) { 487 png_structp* png_ptrp, png_infop* info_ptrp) {
642 // The image is known to be a PNG. Decode enough to know the SkImageInfo. 488 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
643 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, 489 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
644 sk_error_fn, sk_warning_fn); 490 sk_error_fn, sk_warning_fn);
645 if (!png_ptr) { 491 if (!png_ptr) {
646 return false; 492 return false;
647 } 493 }
648 494
649 AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec); 495 AutoCleanPng autoClean(png_ptr);
650 496
651 png_infop info_ptr = png_create_info_struct(png_ptr); 497 png_infop info_ptr = png_create_info_struct(png_ptr);
652 if (info_ptr == nullptr) { 498 if (info_ptr == nullptr) {
653 return false; 499 return false;
654 } 500 }
655 501
656 autoClean.setInfoPtr(info_ptr); 502 autoClean.setInfoPtr(info_ptr);
657 503
658 // FIXME: Could we use the return value of setjmp to specify the type of 504 // FIXME: Could we use the return value of setjmp to specify the type of
659 // error? 505 // error?
660 if (setjmp(png_jmpbuf(png_ptr))) { 506 if (setjmp(png_jmpbuf(png_ptr))) {
661 return false; 507 return false;
662 } 508 }
663 509
510 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);
511
664 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 512 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
665 // Hookup our chunkReader so we can see any user-chunks the caller may be in terested in. 513 // Hookup our chunkReader so we can see any user-chunks the caller may be in terested in.
666 // This needs to be installed before we read the png header. Android may st ore ninepatch 514 // This needs to be installed before we read the png header. Android may st ore ninepatch
667 // chunks in the header. 515 // chunks in the header.
668 if (chunkReader) { 516 if (chunkReader) {
669 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte* )"", 0); 517 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte* )"", 0);
670 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use r_chunk); 518 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use r_chunk);
671 } 519 }
672 #endif 520 #endif
673 521
674 const bool decodedBounds = autoClean.decodeBounds(); 522 // The call to png_read_info() gives us all of the information from the
675 523 // PNG file before the first IDAT (image data chunk).
676 if (!decodedBounds) { 524 png_read_info(png_ptr, info_ptr);
677 return false;
678 }
679
680 // On success, decodeBounds releases ownership of png_ptr and info_ptr.
681 if (png_ptrp) {
682 *png_ptrp = png_ptr;
683 }
684 if (info_ptrp) {
685 *info_ptrp = info_ptr;
686 }
687
688 // decodeBounds takes care of setting outCodec
689 if (outCodec) {
690 SkASSERT(*outCodec);
691 }
692 return true;
693 }
694
695 void AutoCleanPng::infoCallback() {
696 png_uint_32 origWidth, origHeight; 525 png_uint_32 origWidth, origHeight;
697 int bitDepth, encodedColorType; 526 int bitDepth, encodedColorType;
698 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, 527 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
699 &encodedColorType, nullptr, nullptr, nullptr); 528 &encodedColorType, nullptr, nullptr, nullptr);
700 529
701 // Tell libpng to strip 16 bit/color files down to 8 bits/color. 530 // Tell libpng to strip 16 bit/color files down to 8 bits/color.
702 // TODO: Should we handle this in SkSwizzler? Could this also benefit 531 // TODO: Should we handle this in SkSwizzler? Could this also benefit
703 // RAW decodes? 532 // RAW decodes?
704 if (bitDepth == 16) { 533 if (bitDepth == 16) {
705 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType); 534 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
706 png_set_strip_16(fPng_ptr); 535 png_set_strip_16(png_ptr);
707 } 536 }
708 537
709 // Now determine the default colorType and alphaType and set the required tr ansforms. 538 // Now determine the default colorType and alphaType and set the required tr ansforms.
710 // Often, we depend on SkSwizzler to perform any transforms that we need. H owever, we 539 // Often, we depend on SkSwizzler to perform any transforms that we need. H owever, we
711 // still depend on libpng for many of the rare and PNG-specific cases. 540 // still depend on libpng for many of the rare and PNG-specific cases.
712 SkEncodedInfo::Color color; 541 SkEncodedInfo::Color color;
713 SkEncodedInfo::Alpha alpha; 542 SkEncodedInfo::Alpha alpha;
714 switch (encodedColorType) { 543 switch (encodedColorType) {
715 case PNG_COLOR_TYPE_PALETTE: 544 case PNG_COLOR_TYPE_PALETTE:
716 // Extract multiple pixels with bit depths of 1, 2, and 4 from a sin gle 545 // Extract multiple pixels with bit depths of 1, 2, and 4 from a sin gle
717 // byte into separate bytes (useful for paletted and grayscale image s). 546 // byte into separate bytes (useful for paletted and grayscale image s).
718 if (bitDepth < 8) { 547 if (bitDepth < 8) {
719 // TODO: Should we use SkSwizzler here? 548 // TODO: Should we use SkSwizzler here?
720 png_set_packing(fPng_ptr); 549 png_set_packing(png_ptr);
721 } 550 }
722 551
723 color = SkEncodedInfo::kPalette_Color; 552 color = SkEncodedInfo::kPalette_Color;
724 // Set the alpha depending on if a transparency chunk exists. 553 // Set the alpha depending on if a transparency chunk exists.
725 alpha = png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS) ? 554 alpha = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
726 SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alph a; 555 SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alph a;
727 break; 556 break;
728 case PNG_COLOR_TYPE_RGB: 557 case PNG_COLOR_TYPE_RGB:
729 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { 558 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
730 // Convert to RGBA if transparency chunk exists. 559 // Convert to RGBA if transparency chunk exists.
731 png_set_tRNS_to_alpha(fPng_ptr); 560 png_set_tRNS_to_alpha(png_ptr);
732 color = SkEncodedInfo::kRGBA_Color; 561 color = SkEncodedInfo::kRGBA_Color;
733 alpha = SkEncodedInfo::kBinary_Alpha; 562 alpha = SkEncodedInfo::kBinary_Alpha;
734 } else { 563 } else {
735 color = SkEncodedInfo::kRGB_Color; 564 color = SkEncodedInfo::kRGB_Color;
736 alpha = SkEncodedInfo::kOpaque_Alpha; 565 alpha = SkEncodedInfo::kOpaque_Alpha;
737 } 566 }
738 break; 567 break;
739 case PNG_COLOR_TYPE_GRAY: 568 case PNG_COLOR_TYPE_GRAY:
740 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/p ixel. 569 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/p ixel.
741 if (bitDepth < 8) { 570 if (bitDepth < 8) {
742 // TODO: Should we use SkSwizzler here? 571 // TODO: Should we use SkSwizzler here?
743 png_set_expand_gray_1_2_4_to_8(fPng_ptr); 572 png_set_expand_gray_1_2_4_to_8(png_ptr);
744 } 573 }
745 574
746 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { 575 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
747 png_set_tRNS_to_alpha(fPng_ptr); 576 png_set_tRNS_to_alpha(png_ptr);
748 color = SkEncodedInfo::kGrayAlpha_Color; 577 color = SkEncodedInfo::kGrayAlpha_Color;
749 alpha = SkEncodedInfo::kBinary_Alpha; 578 alpha = SkEncodedInfo::kBinary_Alpha;
750 } else { 579 } else {
751 color = SkEncodedInfo::kGray_Color; 580 color = SkEncodedInfo::kGray_Color;
752 alpha = SkEncodedInfo::kOpaque_Alpha; 581 alpha = SkEncodedInfo::kOpaque_Alpha;
753 } 582 }
754 break; 583 break;
755 case PNG_COLOR_TYPE_GRAY_ALPHA: 584 case PNG_COLOR_TYPE_GRAY_ALPHA:
756 color = SkEncodedInfo::kGrayAlpha_Color; 585 color = SkEncodedInfo::kGrayAlpha_Color;
757 alpha = SkEncodedInfo::kUnpremul_Alpha; 586 alpha = SkEncodedInfo::kUnpremul_Alpha;
758 break; 587 break;
759 case PNG_COLOR_TYPE_RGBA: 588 case PNG_COLOR_TYPE_RGBA:
760 color = SkEncodedInfo::kRGBA_Color; 589 color = SkEncodedInfo::kRGBA_Color;
761 alpha = SkEncodedInfo::kUnpremul_Alpha; 590 alpha = SkEncodedInfo::kUnpremul_Alpha;
762 break; 591 break;
763 default: 592 default:
764 // All the color types have been covered above. 593 // All the color types have been covered above.
765 SkASSERT(false); 594 SkASSERT(false);
766 color = SkEncodedInfo::kRGBA_Color; 595 color = SkEncodedInfo::kRGBA_Color;
767 alpha = SkEncodedInfo::kUnpremul_Alpha; 596 alpha = SkEncodedInfo::kUnpremul_Alpha;
768 } 597 }
769 598
770 const int numberPasses = png_set_interlace_handling(fPng_ptr); 599 int numberPasses = png_set_interlace_handling(png_ptr);
771 600
772 if (fOutCodec) { 601 autoClean.release();
773 SkASSERT(nullptr == *fOutCodec); 602 if (png_ptrp) {
774 sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr); 603 *png_ptrp = png_ptr;
604 }
605 if (info_ptrp) {
606 *info_ptrp = info_ptr;
607 }
608
609 if (outCodec) {
610 sk_sp<SkColorSpace> colorSpace = read_color_space(png_ptr, info_ptr);
775 if (!colorSpace) { 611 if (!colorSpace) {
776 // Treat unmarked pngs as sRGB. 612 // Treat unmarked pngs as sRGB.
777 colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); 613 colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
778 } 614 }
615
779 SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8); 616 SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
617
780 if (1 == numberPasses) { 618 if (1 == numberPasses) {
781 *fOutCodec = new SkPngNormalDecoder(origWidth, origHeight, info, fSt ream, 619 *outCodec = new SkPngScanlineDecoder(origWidth, origHeight, info, st ream,
782 fChunkReader, fPng_ptr, fInfo_ptr, bitDepth, std::move(color Space)); 620 chunkReader, png_ptr, info_ptr, bitDepth, colorSpace);
783 } else { 621 } else {
784 *fOutCodec = new SkPngInterlacedDecoder(origWidth, origHeight, info, fStream, 622 *outCodec = new SkPngInterlacedScanlineDecoder(origWidth, origHeight , info, stream,
785 fChunkReader, fPng_ptr, fInfo_ptr, bitDepth, std::move(color Space), 623 chunkReader, png_ptr, info_ptr, bitDepth, numberPasses, colo rSpace);
786 numberPasses);
787 } 624 }
788 } 625 }
789 626
790 fDecodedBounds = true; 627 return true;
791 // 1 tells libpng to save any extra data. We may be able to be more efficien t by saving
792 // it ourselves.
793 png_process_data_pause(fPng_ptr, 1);
794
795 // Release the pointers, which are now owned by the codec or the caller is e xpected to
796 // take ownership.
797 this->releasePngPtrs();
798 } 628 }
799 629
800 SkPngCodec::SkPngCodec(int width, int height, const SkEncodedInfo& info, SkStrea m* stream, 630 SkPngCodec::SkPngCodec(int width, int height, const SkEncodedInfo& info, SkStrea m* stream,
801 SkPngChunkReader* chunkReader, png_structp png_ptr, png_i nfop info_ptr, 631 SkPngChunkReader* chunkReader, png_structp png_ptr, png_i nfop info_ptr,
802 int bitDepth, sk_sp<SkColorSpace> colorSpace) 632 int bitDepth, int numberPasses, sk_sp<SkColorSpace> color Space)
803 : INHERITED(width, height, info, stream, colorSpace) 633 : INHERITED(width, height, info, stream, colorSpace)
804 , fPngChunkReader(SkSafeRef(chunkReader)) 634 , fPngChunkReader(SkSafeRef(chunkReader))
805 , fPng_ptr(png_ptr) 635 , fPng_ptr(png_ptr)
806 , fInfo_ptr(info_ptr) 636 , fInfo_ptr(info_ptr)
637 , fNumberPasses(numberPasses)
807 , fBitDepth(bitDepth) 638 , fBitDepth(bitDepth)
808 {} 639 {}
809 640
810 SkPngCodec::~SkPngCodec() { 641 SkPngCodec::~SkPngCodec() {
811 this->destroyReadStruct(); 642 this->destroyReadStruct();
812 } 643 }
813 644
814 void SkPngCodec::destroyReadStruct() { 645 void SkPngCodec::destroyReadStruct() {
815 if (fPng_ptr) { 646 if (fPng_ptr) {
816 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr 647 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
817 SkASSERT(fInfo_ptr); 648 SkASSERT(fInfo_ptr);
818 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr); 649 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr);
819 fPng_ptr = nullptr; 650 fPng_ptr = nullptr;
820 fInfo_ptr = nullptr; 651 fInfo_ptr = nullptr;
821 } 652 }
822 } 653 }
823 654
824 /////////////////////////////////////////////////////////////////////////////// 655 ///////////////////////////////////////////////////////////////////////////////
825 // Getting the pixels 656 // Getting the pixels
826 /////////////////////////////////////////////////////////////////////////////// 657 ///////////////////////////////////////////////////////////////////////////////
827 658
828 bool SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 659 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
829 const Options& options, 660 const Options& options,
830 SkPMColor ctable[], 661 SkPMColor ctable[],
831 int* ctableCount) { 662 int* ctableCount) {
663 // FIXME: Could we use the return value of setjmp to specify the type of
664 // error?
832 if (setjmp(png_jmpbuf(fPng_ptr))) { 665 if (setjmp(png_jmpbuf(fPng_ptr))) {
833 return false; 666 SkCodecPrintf("setjmp long jump!\n");
667 return kInvalidInput;
834 } 668 }
835 png_read_update_info(fPng_ptr, fInfo_ptr); 669 png_read_update_info(fPng_ptr, fInfo_ptr);
836 670
837 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { 671 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
838 if (!this->createColorTable(requestedInfo.colorType(), 672 if (!this->createColorTable(requestedInfo.colorType(),
839 kPremul_SkAlphaType == requestedInfo.alphaType(), ctableCount)) { 673 kPremul_SkAlphaType == requestedInfo.alphaType(), ctableCount)) {
840 return false; 674 return kInvalidInput;
841 } 675 }
842 } 676 }
843 677
844 // Copy the color table to the client if they request kIndex8 mode 678 // Copy the color table to the client if they request kIndex8 mode
845 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); 679 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
846 680
847 // Create the swizzler. SkPngCodec retains ownership of the color table. 681 // Create the swizzler. SkPngCodec retains ownership of the color table.
848 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 682 const SkPMColor* colors = get_color_ptr(fColorTable.get());
849 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, r equestedInfo, 683 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, r equestedInfo,
850 options)); 684 options));
851 SkASSERT(fSwizzler); 685 SkASSERT(fSwizzler);
852 686
853 return true; 687 return kSuccess;
854 } 688 }
855 689
856 690
857 bool SkPngCodec::onRewind() { 691 bool SkPngCodec::onRewind() {
858 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 692 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
859 // succeeds, they will be repopulated, and if it fails, they will 693 // succeeds, they will be repopulated, and if it fails, they will
860 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 694 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
861 // come through this function which will rewind and again attempt 695 // come through this function which will rewind and again attempt
862 // to reinitialize them. 696 // to reinitialize them.
863 this->destroyReadStruct(); 697 this->destroyReadStruct();
(...skipping 15 matching lines...) Expand all
879 int* rowsDecoded) { 713 int* rowsDecoded) {
880 if (!conversion_possible(requestedInfo, this->getInfo())) { 714 if (!conversion_possible(requestedInfo, this->getInfo())) {
881 return kInvalidConversion; 715 return kInvalidConversion;
882 } 716 }
883 if (options.fSubset) { 717 if (options.fSubset) {
884 // Subsets are not supported. 718 // Subsets are not supported.
885 return kUnimplemented; 719 return kUnimplemented;
886 } 720 }
887 721
888 // Note that ctable and ctableCount may be modified if there is a color tabl e 722 // Note that ctable and ctableCount may be modified if there is a color tabl e
889 if (!this->initializeSwizzler(requestedInfo, options, ctable, ctableCount)) { 723 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl e, ctableCount);
890 return kInvalidInput; // or parameters? 724 if (result != kSuccess) {
725 return result;
891 } 726 }
892 727
893 return this->decodeAllRows(dst, dstRowBytes, rowsDecoded); 728 const int width = requestedInfo.width();
894 } 729 const int height = requestedInfo.height();
730 const int bpp = bytes_per_pixel(this->getEncodedInfo().bitsPerPixel());
731 const size_t srcRowBytes = width * bpp;
895 732
896 SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, 733 // FIXME: Could we use the return value of setjmp to specify the type of
897 void* dst, size_t rowBytes, const SkCodec::Options& options, 734 // error?
898 SkPMColor* ctable, int* ctableCount) { 735 int row = 0;
899 if (!conversion_possible(dstInfo, this->getInfo())) { 736 // This must be declared above the call to setjmp to avoid memory leaks on i ncomplete images.
900 return kInvalidConversion; 737 SkAutoTMalloc<uint8_t> storage;
738 if (setjmp(png_jmpbuf(fPng_ptr))) {
739 // Assume that any error that occurs while reading rows is caused by an incomplete input.
740 if (fNumberPasses > 1) {
741 // FIXME (msarett): Handle incomplete interlaced pngs.
742 return (row == height) ? kSuccess : kInvalidInput;
743 }
744 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium,
745 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192
746 // bytes), and if we can't fill the buffer, we immediately fail.
747 // For example, if we try to read 8192 bytes, and the image (incorrectly ) only contains
748 // half that, which may have been enough to contain a non-zero number of lines, we fail
749 // when we could have decoded a few more lines and then failed.
750 // The read function that we provide for libpng has no way of indicating that we have
751 // made a partial read.
752 // Making our buffer size smaller improves our incomplete decodes, but w hat impact does
753 // it have on regular decode performance? Should we investigate using a different API
754 // instead of png_read_row? Chromium uses png_process_data.
755 *rowsDecoded = row;
756 return (row == height) ? kSuccess : kIncompleteInput;
901 } 757 }
902 758
903 if (!this->initializeSwizzler(dstInfo, options, ctable, ctableCount)) { 759 // FIXME: We could split these out based on subclass.
904 return kInvalidInput; 760 void* dstRow = dst;
761 if (fNumberPasses > 1) {
762 storage.reset(height * srcRowBytes);
763 uint8_t* const base = storage.get();
764
765 for (int i = 0; i < fNumberPasses; i++) {
766 uint8_t* srcRow = base;
767 for (int y = 0; y < height; y++) {
768 png_read_row(fPng_ptr, srcRow, nullptr);
769 srcRow += srcRowBytes;
770 }
771 }
772
773 // Now swizzle it.
774 uint8_t* srcRow = base;
775 for (; row < height; row++) {
776 fSwizzler->swizzle(dstRow, srcRow);
777 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
778 srcRow += srcRowBytes;
779 }
780 } else {
781 storage.reset(srcRowBytes);
782 uint8_t* srcRow = storage.get();
783 for (; row < height; row++) {
784 png_read_row(fPng_ptr, srcRow, nullptr);
785 fSwizzler->swizzle(dstRow, srcRow);
786 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
787 }
905 } 788 }
906 789
907 int firstRow, lastRow; 790 // read rest of file, and get additional comment and time chunks in info_ptr
908 if (options.fSubset) { 791 png_read_end(fPng_ptr, fInfo_ptr);
909 firstRow = options.fSubset->top(); 792
910 lastRow = options.fSubset->bottom() - 1;
911 } else {
912 firstRow = 0;
913 lastRow = dstInfo.height() - 1;
914 }
915 this->setRange(firstRow, lastRow, dst, rowBytes);
916 return kSuccess; 793 return kSuccess;
917 } 794 }
918 795
919 SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) {
920 return this->decode(rowsDecoded);
921 }
922
923 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { 796 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const {
924 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); 797 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
925 if (colorPtr) { 798 if (colorPtr) {
926 return get_color_table_fill_value(colorType, colorPtr, 0); 799 return get_color_table_fill_value(colorType, colorPtr, 0);
927 } 800 }
928 return INHERITED::onGetFillValue(colorType); 801 return INHERITED::onGetFillValue(colorType);
929 } 802 }
930 803
931 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead er) { 804 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead er) {
932 SkAutoTDelete<SkStream> streamDeleter(stream); 805 SkAutoTDelete<SkStream> streamDeleter(stream);
933 806
934 SkCodec* outCodec = nullptr; 807 SkCodec* outCodec;
935 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) { 808 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) {
936 // Codec has taken ownership of the stream. 809 // Codec has taken ownership of the stream.
937 SkASSERT(outCodec); 810 SkASSERT(outCodec);
938 streamDeleter.release(); 811 streamDeleter.release();
939 return outCodec; 812 return outCodec;
940 } 813 }
941 814
942 return nullptr; 815 return nullptr;
943 } 816 }
944 #endif
OLDNEW
« no previous file with comments | « src/codec/SkPngCodec.h ('k') | src/codec/SkSampledCodec.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698