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

Unified Diff: src/codec/SkCodec_libpng.cpp

Issue 1332053002: Fill incomplete images in SkCodec parent class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: src/codec/SkCodec_libpng.cpp
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index 2ba2d5bb9f2bed42209d9c2ca5b0ce4ce127bba0..7896cc3bba6df7df2016ce707808b6d6cd3278bd 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -367,6 +367,7 @@ SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream,
: INHERITED(info, stream)
, fPng_ptr(png_ptr)
, fInfo_ptr(info_ptr)
+ , fRow(0)
, fSrcConfig(SkSwizzler::kUnknown)
, fNumberPasses(INVALID_NUMBER_PASSES)
, fReallyHasAlpha(false)
@@ -494,8 +495,19 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
// FIXME: Could we use the return value of setjmp to specify the type of
// error?
if (setjmp(png_jmpbuf(fPng_ptr))) {
- SkCodecPrintf("setjmp long jump!\n");
- return kInvalidInput;
+ // 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;
+ }
+ // 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
+ // bytes), and if we can't fill the buffer, we immediately fail. Making our buffer size
scroggo 2015/09/22 18:02:48 Does this mean, for example, that we try to read 8
msarett 2015/09/23 13:22:40 Yes that is exactly what the problem is.
scroggo 2015/09/25 15:55:05 Could you add that to the description?
msarett 2015/10/01 12:44:51 Done.
+ // smaller would help, but what impact would it have on regular decode performance? Should
+ // we investigate using a different API than png_read_row(s). Chromium uses
+ // png_process_data.
+ this->setIncompleteScanlines(requestedInfo.height() - fRow);
scroggo 2015/09/22 18:02:48 I always get confused when dealing with setjmp, so
msarett 2015/09/23 13:22:40 Yes this works! Clever!
scroggo 2015/09/25 15:55:05 Just to make sure, did you test this? Can we add a
msarett 2015/10/01 12:44:51 Yes I tested this. I have been testing by decodin
scroggo 2015/10/01 14:48:31 Possibly - the advantage to including it in CodexT
msarett 2015/10/01 18:14:13 I will add a single incomplete image to resources
+ return kIncompleteInput;
}
SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
@@ -529,7 +541,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
} else {
storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConfig));
uint8_t* srcRow = static_cast<uint8_t*>(storage.get());
- for (int y = 0; y < requestedInfo.height(); y++) {
+ for (fRow = 0; fRow < requestedInfo.height(); fRow++) {
png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow));
dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
@@ -550,10 +562,18 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
return kSuccess;
}
+uint32_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const {
+ const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
+ if (colorPtr) {
+ return get_color_table_fill_value(dstInfo.colorType(), colorPtr, 0);
+ }
+ return INHERITED::onGetFillValue(dstInfo);
+}
+
class SkPngScanlineDecoder : public SkScanlineDecoder {
public:
- SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec)
- : INHERITED(srcInfo)
+ SkPngScanlineDecoder(SkPngCodec* codec)
+ : INHERITED(codec, codec->getInfo())
, fCodec(codec)
, fHasAlpha(false)
{}
@@ -577,7 +597,7 @@ public:
}
const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, options, ctable,
- ctableCount);
+ ctableCount);
if (result != SkCodec::kSuccess) {
return result;
}
@@ -589,35 +609,35 @@ public:
return SkCodec::kSuccess;
}
- SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) override {
+ uint32_t onGetScanlines(void* dst, int count, size_t rowBytes) override {
+ // Assume that an error in libpng indicates an incomplete input.
if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
SkCodecPrintf("setjmp long jump!\n");
- return SkCodec::kInvalidInput;
+ return fCodec->fRow;
}
void* dstRow = dst;
- for (int i = 0; i < count; i++) {
+ for (fCodec->fRow = 0; fCodec->fRow < count; fCodec->fRow++) {
png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1);
fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow, fSrcRow));
dstRow = SkTAddOffset<void>(dstRow, rowBytes);
}
- return SkCodec::kSuccess;
+ return fCodec->fRow;
}
- SkCodec::Result onSkipScanlines(int count) override {
- // FIXME: Could we use the return value of setjmp to specify the type of
- // error?
+ uint32_t onSkipScanlines(int count) override {
+ // Assume that an error in libpng indicates an incomplete input.
if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
SkCodecPrintf("setjmp long jump!\n");
- return SkCodec::kInvalidInput;
+ return fCodec->fRow;
}
//there is a potential tradeoff of memory vs speed created by putting this in a loop.
//calling png_read_rows in a loop is insignificantly slower than calling it once with count
//as png_read_rows has it's own loop which calls png_read_row count times.
- for (int i = 0; i < count; i++) {
+ for (fCodec->fRow = 0; fCodec->fRow < count; fCodec->fRow++) {
png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1);
}
- return SkCodec::kSuccess;
+ return fCodec->fRow;
}
bool onReallyHasAlpha() const override { return fHasAlpha; }
@@ -628,7 +648,7 @@ public:
private:
- SkAutoTDelete<SkPngCodec> fCodec;
+ SkPngCodec* fCodec; // Owned by parent class
bool fHasAlpha;
SkAutoMalloc fStorage;
uint8_t* fSrcRow;
@@ -639,12 +659,12 @@ private:
class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder {
public:
- SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec)
- : INHERITED(srcInfo)
+ SkPngInterlacedScanlineDecoder(SkPngCodec* codec)
+ : INHERITED(codec, codec->getInfo())
, fCodec(codec)
, fHasAlpha(false)
, fCurrentRow(0)
- , fHeight(srcInfo.height())
+ , fHeight(codec->getInfo().height())
, fCanSkipRewind(false)
{}
@@ -668,7 +688,7 @@ public:
}
const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, options, ctable,
- ctableCount);
+ ctableCount);
if (result != SkCodec::kSuccess) {
return result;
}
@@ -684,7 +704,7 @@ public:
return SkCodec::kSuccess;
}
- SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
+ uint32_t onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
// rewind stream if have previously called onGetScanlines,
// since we need entire progressive image to get scanlines
if (fCanSkipRewind) {
@@ -692,12 +712,15 @@ public:
// Next time onGetScanlines is called, we will need to rewind.
fCanSkipRewind = false;
} else if (!fCodec->rewindIfNeeded()) {
- return SkCodec::kCouldNotRewind;
+ return 0;
}
if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
SkCodecPrintf("setjmp long jump!\n");
- return SkCodec::kInvalidInput;
+ // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
+ // we may be able to report that all of the memory has been initialized. Even if we
+ // fail on the first pass, we can still report than some scanlines are initialized.
+ return 0;
}
const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr);
SkAutoMalloc storage(count * fSrcRowBytes);
@@ -728,13 +751,13 @@ public:
srcRow += fSrcRowBytes;
}
fCurrentRow += count;
- return SkCodec::kSuccess;
+ return count;
}
- SkCodec::Result onSkipScanlines(int count) override {
+ uint32_t onSkipScanlines(int count) override {
//when ongetScanlines is called it will skip to fCurrentRow
fCurrentRow += count;
- return SkCodec::kSuccess;
+ return count;
}
bool onReallyHasAlpha() const override { return fHasAlpha; }
@@ -748,7 +771,7 @@ public:
}
private:
- SkAutoTDelete<SkPngCodec> fCodec;
+ SkPngCodec* fCodec; // Owned by parent class
bool fHasAlpha;
int fCurrentRow;
int fHeight;
@@ -777,12 +800,11 @@ SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) {
codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr);
SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES);
- const SkImageInfo& srcInfo = codec->getInfo();
if (codec->fNumberPasses > 1) {
// interlaced image
- return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach());
+ return new SkPngInterlacedScanlineDecoder(codec.detach());
}
- return new SkPngScanlineDecoder(srcInfo, codec.detach());
+ return new SkPngScanlineDecoder(codec.detach());
}

Powered by Google App Engine
This is Rietveld 408576698