| Index: src/codec/SkPngCodec.cpp
|
| diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp
|
| index 232373c04407c63c2b391c148a7053db9e9d62e9..797178948fba8c6d05b07d96fabbb6e5a49811c8 100644
|
| --- a/src/codec/SkPngCodec.cpp
|
| +++ b/src/codec/SkPngCodec.cpp
|
| @@ -426,6 +426,11 @@ SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
|
| SkASSERT(false);
|
| }
|
|
|
| + // If we are not performing a subset decode, and the swizzle will not change the
|
| + // number of bytes per pixel, we can swizzle in place.
|
| + fInPlaceSwizzle = (SkSwizzler::BytesPerPixel(fSrcConfig) ==
|
| + SkColorTypeBytesPerPixel(requestedInfo.colorType()) && !options.fSubset);
|
| +
|
| // Copy the color table to the client if they request kIndex8 mode
|
| copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
|
|
|
| @@ -475,6 +480,11 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
|
| if (result != kSuccess) {
|
| return result;
|
| }
|
| +
|
| + const int width = requestedInfo.width();
|
| + const int height = requestedInfo.height();
|
| + const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
|
| +
|
| // FIXME: Could we use the return value of setjmp to specify the type of
|
| // error?
|
| int row = 0;
|
| @@ -484,7 +494,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
|
| // Assume that any error that occurs while reading rows is caused by an incomplete input.
|
| if (fNumberPasses > 1) {
|
| // FIXME (msarett): Handle incomplete interlaced pngs.
|
| - return kInvalidInput;
|
| + return row == height ? kSuccess : kInvalidInput;
|
| }
|
| // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium,
|
| // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192
|
| @@ -498,25 +508,20 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
|
| // it have on regular decode performance? Should we investigate using a different API
|
| // instead of png_read_row(s)? Chromium uses png_process_data.
|
| *rowsDecoded = row;
|
| - return kIncompleteInput;
|
| + return row == height ? kSuccess : kIncompleteInput;
|
| }
|
|
|
| // FIXME: We could split these out based on subclass.
|
| void* dstRow = dst;
|
| if (fNumberPasses > 1) {
|
| - const int width = requestedInfo.width();
|
| - const int height = requestedInfo.height();
|
| - const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
|
| - const size_t srcRowBytes = width * bpp;
|
| -
|
| - storage.reset(width * height * bpp);
|
| - uint8_t* const base = storage.get();
|
| + uint8_t* const base = fInPlaceSwizzle ? (uint8_t*) dstRow :
|
| + storage.reset(width * height * bpp);
|
| + const size_t srcRowBytes = fInPlaceSwizzle ? dstRowBytes : width * bpp;
|
|
|
| for (int i = 0; i < fNumberPasses; i++) {
|
| uint8_t* srcRow = base;
|
| for (int y = 0; y < height; y++) {
|
| - uint8_t* bmRow = srcRow;
|
| - png_read_rows(fPng_ptr, &bmRow, nullptr, 1);
|
| + png_read_rows(fPng_ptr, &srcRow, nullptr, 1);
|
| srcRow += srcRowBytes;
|
| }
|
| }
|
| @@ -529,21 +534,16 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
|
| srcRow += srcRowBytes;
|
| }
|
| } else {
|
| - storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConfig));
|
| - uint8_t* srcRow = storage.get();
|
| + uint8_t* srcRow = fInPlaceSwizzle ? (uint8_t*) dstRow : storage.reset(width * bpp);
|
| + const size_t srcRowBytes = fInPlaceSwizzle ? dstRowBytes : 0;
|
| for (; row < requestedInfo.height(); row++) {
|
| png_read_rows(fPng_ptr, &srcRow, nullptr, 1);
|
| - // FIXME: Only call IsOpaque once, outside the loop. Same for onGetScanlines.
|
| fSwizzler->swizzle(dstRow, srcRow);
|
| dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
|
| + srcRow += srcRowBytes;
|
| }
|
| }
|
|
|
| - if (setjmp(png_jmpbuf(fPng_ptr))) {
|
| - // We've already read all the scanlines. This is a success.
|
| - return kSuccess;
|
| - }
|
| -
|
| // read rest of file, and get additional comment and time chunks in info_ptr
|
| png_read_end(fPng_ptr, fInfo_ptr);
|
|
|
| @@ -595,8 +595,9 @@ public:
|
|
|
| void* dstRow = dst;
|
| for (; row < count; row++) {
|
| - png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
|
| - this->swizzler()->swizzle(dstRow, fSrcRow);
|
| + uint8_t* srcRow = this->inPlaceSwizzle() ? (uint8_t*) dstRow : fSrcRow;
|
| + png_read_rows(this->png_ptr(), &srcRow, nullptr, 1);
|
| + this->swizzler()->swizzle(dstRow, srcRow);
|
| dstRow = SkTAddOffset<void>(dstRow, rowBytes);
|
| }
|
|
|
| @@ -690,8 +691,10 @@ public:
|
| // fail on the first pass, we can still report than some scanlines are initialized.
|
| return 0;
|
| }
|
| - SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
|
| - uint8_t* storagePtr = storage.get();
|
| + SkAutoTMalloc<uint8_t> storage;
|
| + uint8_t* const base = this->inPlaceSwizzle() ? (uint8_t*) dst :
|
| + storage.reset(count * fSrcRowBytes);
|
| + const size_t srcRowBytes = this->inPlaceSwizzle() ? dstRowBytes : fSrcRowBytes;
|
| uint8_t* srcRow;
|
| const int startRow = this->nextScanline();
|
| for (int i = 0; i < this->numberPasses(); i++) {
|
| @@ -700,10 +703,10 @@ public:
|
| png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
|
| }
|
| // read rows we care about into buffer
|
| - srcRow = storagePtr;
|
| + uint8_t* srcRow = base;
|
| for (int y = 0; y < count; y++) {
|
| png_read_rows(this->png_ptr(), &srcRow, nullptr, 1);
|
| - srcRow += fSrcRowBytes;
|
| + srcRow += srcRowBytes;
|
| }
|
| // read rows we don't want into garbage buffer
|
| for (int y = 0; y < fHeight - startRow - count; y++) {
|
| @@ -711,12 +714,12 @@ public:
|
| }
|
| }
|
| //swizzle the rows we care about
|
| - srcRow = storagePtr;
|
| + srcRow = base;
|
| void* dstRow = dst;
|
| for (int y = 0; y < count; y++) {
|
| this->swizzler()->swizzle(dstRow, srcRow);
|
| dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
|
| - srcRow += fSrcRowBytes;
|
| + srcRow += srcRowBytes;
|
| }
|
|
|
| return count;
|
|
|