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

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: Use aligned memory in swizzler test Created 5 years, 2 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
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/codec/SkCodec_wbmp.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/codec/SkCodec_libpng.cpp
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index ee8d49263ff3e1ee8031da3a46b4c748a6e849c2..e828e2499922cb2badc789a5e8914660a8951783 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -466,7 +466,8 @@ bool SkPngCodec::onRewind() {
SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
size_t dstRowBytes, const Options& options,
- SkPMColor ctable[], int* ctableCount) {
+ SkPMColor ctable[], int* ctableCount,
+ int* rowsDecoded) {
if (!conversion_possible(requestedInfo, this->getInfo())) {
return kInvalidConversion;
}
@@ -483,14 +484,32 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
}
// FIXME: Could we use the return value of setjmp to specify the type of
// error?
+ int row = 0;
+ // This must be declared above the call to setjmp to avoid memory leaks on incomplete images.
+ SkAutoMalloc storage;
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.
+ // For example, if we try to read 8192 bytes, and the image (incorrectly) only contains
+ // half that, which may have been enough to contain a non-zero number of lines, we fail
+ // when we could have decoded a few more lines and then failed.
+ // The read function that we provide for libpng has no way of indicating that we have
+ // made a partial read.
+ // Making our buffer size smaller improves our incomplete decodes, but what impact does
+ // 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;
}
bool hasAlpha = false;
// FIXME: We could split these out based on subclass.
- SkAutoMalloc storage;
void* dstRow = dst;
if (fNumberPasses > 1) {
const int width = requestedInfo.width();
@@ -520,7 +539,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 (; row < requestedInfo.height(); row++) {
png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
// FIXME: Only call IsOpaque once, outside the loop. Same for onGetScanlines.
hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow));
@@ -549,6 +568,14 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
return kSuccess;
}
+uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType) const {
+ const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
+ if (colorPtr) {
+ return get_color_table_fill_value(colorType, colorPtr, 0);
+ }
+ return INHERITED::onGetFillValue(colorType, alphaType);
+}
+
bool SkPngCodec::onReallyHasAlpha() const {
switch (fAlphaState) {
case kOpaque_AlphaState:
@@ -603,15 +630,17 @@ public:
return kSuccess;
}
- Result onGetScanlines(void* dst, int count, size_t rowBytes) override {
+ int onGetScanlines(void* dst, int count, size_t rowBytes) override {
+ // Assume that an error in libpng indicates an incomplete input.
+ int row = 0;
if (setjmp(png_jmpbuf(this->png_ptr()))) {
SkCodecPrintf("setjmp long jump!\n");
- return kInvalidInput;
+ return row;
}
void* dstRow = dst;
bool hasAlpha = false;
- for (int i = 0; i < count; i++) {
+ for (; row < count; row++) {
png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow));
dstRow = SkTAddOffset<void>(dstRow, rowBytes);
@@ -626,23 +655,22 @@ public:
// Otherwise, the AlphaState is unchanged.
}
- return kSuccess;
+ return row;
}
- Result onSkipScanlines(int count) override {
- // FIXME: Could we use the return value of setjmp to specify the type of
- // error?
+ bool onSkipScanlines(int count) override {
+ // Assume that an error in libpng indicates an incomplete input.
if (setjmp(png_jmpbuf(this->png_ptr()))) {
SkCodecPrintf("setjmp long jump!\n");
- return kInvalidInput;
+ return false;
}
//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 (int row = 0; row < count; row++) {
png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
}
- return SkCodec::kSuccess;
+ return true;
}
AlphaState alphaInScanlineDecode() const override {
@@ -694,7 +722,7 @@ public:
return SkCodec::kSuccess;
}
- Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
+ int 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) {
@@ -707,7 +735,7 @@ public:
// decoding is the exception, since it needs to rewind between
// calls to getScanlines. Keep track of fCurrScanline, to undo the
// reset.
- const int currScanline = this->onNextScanline();
+ const int currScanline = this->nextScanline();
// This method would never be called if currScanline is -1
SkASSERT(currScanline != -1);
@@ -719,12 +747,15 @@ public:
if (setjmp(png_jmpbuf(this->png_ptr()))) {
SkCodecPrintf("setjmp long jump!\n");
- return 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;
}
SkAutoMalloc storage(count * fSrcRowBytes);
uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
uint8_t* srcRow;
- const int startRow = this->onNextScanline();
+ const int startRow = this->nextScanline();
for (int i = 0; i < this->numberPasses(); i++) {
// read rows we planned to skip into garbage row
for (int y = 0; y < startRow; y++){
@@ -760,12 +791,12 @@ public:
// Otherwise, the AlphaState is unchanged.
}
- return kSuccess;
+ return count;
}
- SkCodec::Result onSkipScanlines(int count) override {
+ bool onSkipScanlines(int count) override {
// The non-virtual version will update fCurrScanline.
- return SkCodec::kSuccess;
+ return true;
}
AlphaState alphaInScanlineDecode() const override {
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/codec/SkCodec_wbmp.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698