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; |