Index: src/images/SkImageDecoder_libjpeg.cpp |
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp |
index 21e96be2d3049e091a48ef1728bf7554522ad684..10466640046ce60f9876b6714312cc7a213e95f7 100644 |
--- a/src/images/SkImageDecoder_libjpeg.cpp |
+++ b/src/images/SkImageDecoder_libjpeg.cpp |
@@ -238,7 +238,7 @@ protected: |
virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE; |
virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE; |
#endif |
- virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
+ virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
virtual bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], |
void* planes[3], size_t rowBytes[3], |
SkYUVColorSpace* colorSpace) SK_OVERRIDE; |
@@ -325,9 +325,11 @@ static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, |
} |
#endif |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
// This guy exists just to aid in debugging, as it allows debuggers to just |
// set a break-point in one place to see all error exists. |
-static bool return_false(const jpeg_decompress_struct& cinfo, |
+static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo, |
int width, int height, const char caller[]) { |
if (!(c_suppressJPEGImageDecoderErrors)) { |
char buffer[JMSG_LENGTH_MAX]; |
@@ -335,14 +337,28 @@ static bool return_false(const jpeg_decompress_struct& cinfo, |
SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", |
cinfo.err->msg_code, buffer, caller, width, height); |
} |
- return false; // must always return false |
+} |
+ |
+static bool return_false(const jpeg_decompress_struct& cinfo, |
+ const char caller[]) { |
+ print_jpeg_decoder_errors(cinfo, 0, 0, caller); |
+ return false; |
} |
static bool return_false(const jpeg_decompress_struct& cinfo, |
const SkBitmap& bm, const char caller[]) { |
- return return_false(cinfo, bm.width(), bm.height(), caller); |
+ print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); |
+ return false; |
+} |
+ |
+static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo, |
+ const SkBitmap& bm, const char caller[]) { |
+ print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); |
+ return SkImageDecoder::kFailure; |
} |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
// Convert a scanline of CMYK samples to RGBX in place. Note that this |
// method moves the "scanline" pointer in its processing |
static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { |
@@ -491,7 +507,6 @@ static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo, |
#endif |
} |
- |
/** |
Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y. |
Used when decoding fails partway through reading scanlines to fill |
@@ -537,7 +552,7 @@ static bool get_src_config(const jpeg_decompress_struct& cinfo, |
return true; |
} |
-bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
+SkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
#ifdef TIME_DECODE |
SkAutoTime atm("JPEG Decode"); |
#endif |
@@ -553,7 +568,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
// All objects need to be instantiated before this setjmp call so that |
// they will be cleaned up properly if an error occurs. |
if (setjmp(errorManager.fJmpBuf)) { |
- return return_false(cinfo, *bm, "setjmp"); |
+ return return_failure(cinfo, *bm, "setjmp"); |
} |
initialize_info(&cinfo, &srcManager); |
@@ -561,7 +576,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
int status = jpeg_read_header(&cinfo, true); |
if (status != JPEG_HEADER_OK) { |
- return return_false(cinfo, *bm, "read_header"); |
+ return return_failure(cinfo, *bm, "read_header"); |
} |
/* Try to fulfill the requested sampleSize. Since jpeg can do it (when it |
@@ -588,8 +603,9 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
// individual pixel. It is very unlikely to be opaque, since |
// an opaque A8 bitmap would not be very interesting. |
// Otherwise, a jpeg image is opaque. |
- return bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height, |
- colorType, alphaType)); |
+ bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height, |
+ colorType, alphaType)); |
+ return success ? kSuccess : kFailure; |
} |
/* image_width and image_height are the original dimensions, available |
@@ -613,10 +629,11 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
// individual pixel. It is very unlikely to be opaque, since |
// an opaque A8 bitmap would not be very interesting. |
// Otherwise, a jpeg image is opaque. |
- return bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(), |
- colorType, alphaType)); |
+ bool success = bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(), |
+ colorType, alphaType)); |
+ return success ? kSuccess : kFailure; |
} else { |
- return return_false(cinfo, *bm, "start_decompress"); |
+ return return_failure(cinfo, *bm, "start_decompress"); |
} |
} |
sampleSize = recompute_sampleSize(sampleSize, cinfo); |
@@ -624,7 +641,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER |
// should we allow the Chooser (if present) to pick a colortype for us??? |
if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_height)) { |
- return return_false(cinfo, *bm, "chooseFromOneChoice"); |
+ return return_failure(cinfo, *bm, "chooseFromOneChoice"); |
} |
#endif |
@@ -636,10 +653,10 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), |
colorType, alphaType)); |
if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
- return true; |
+ return kSuccess; |
} |
if (!this->allocPixelRef(bm, NULL)) { |
- return return_false(cinfo, *bm, "allocPixelRef"); |
+ return return_failure(cinfo, *bm, "allocPixelRef"); |
} |
SkAutoLockPixels alp(*bm); |
@@ -662,15 +679,16 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
// so return early. We will return a partial image. |
fill_below_level(cinfo.output_scanline, bm); |
cinfo.output_scanline = cinfo.output_height; |
- break; // Skip to jpeg_finish_decompress() |
+ jpeg_finish_decompress(&cinfo); |
+ return kPartialSuccess; |
} |
if (this->shouldCancelDecode()) { |
- return return_false(cinfo, *bm, "shouldCancelDecode"); |
+ return return_failure(cinfo, *bm, "shouldCancelDecode"); |
} |
rowptr += bpr; |
} |
jpeg_finish_decompress(&cinfo); |
- return true; |
+ return kSuccess; |
} |
#endif |
@@ -679,11 +697,11 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
int srcBytesPerPixel; |
if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { |
- return return_false(cinfo, *bm, "jpeg colorspace"); |
+ return return_failure(cinfo, *bm, "jpeg colorspace"); |
} |
if (!sampler.begin(bm, sc, *this)) { |
- return return_false(cinfo, *bm, "sampler.begin"); |
+ return return_failure(cinfo, *bm, "sampler.begin"); |
} |
SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); |
@@ -691,7 +709,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
// Possibly skip initial rows [sampler.srcY0] |
if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { |
- return return_false(cinfo, *bm, "skip rows"); |
+ return return_failure(cinfo, *bm, "skip rows"); |
} |
// now loop through scanlines until y == bm->height() - 1 |
@@ -703,10 +721,11 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
// so return early. We will return a partial image. |
fill_below_level(y, bm); |
cinfo.output_scanline = cinfo.output_height; |
- break; // Skip to jpeg_finish_decompress() |
+ jpeg_finish_decompress(&cinfo); |
+ return kSuccess; |
} |
if (this->shouldCancelDecode()) { |
- return return_false(cinfo, *bm, "shouldCancelDecode"); |
+ return return_failure(cinfo, *bm, "shouldCancelDecode"); |
} |
if (JCS_CMYK == cinfo.out_color_space) { |
@@ -720,20 +739,22 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { |
} |
if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { |
- return return_false(cinfo, *bm, "skip rows"); |
+ return return_failure(cinfo, *bm, "skip rows"); |
} |
} |
// we formally skip the rest, so we don't get a complaint from libjpeg |
if (!skip_src_rows(&cinfo, srcRow, |
cinfo.output_height - cinfo.output_scanline)) { |
- return return_false(cinfo, *bm, "skip rows"); |
+ return return_failure(cinfo, *bm, "skip rows"); |
} |
jpeg_finish_decompress(&cinfo); |
- return true; |
+ return kSuccess; |
} |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
enum SizeType { |
kSizeForMemoryAllocation_SizeType, |
kActualSize_SizeType |
@@ -878,8 +899,9 @@ static bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size |
} |
JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead); |
- if (scanlinesRead == 0) |
+ if (scanlinesRead == 0) { |
return false; |
+ } |
if (hasYLastRow) { |
memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth); |
@@ -917,7 +939,7 @@ bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentS |
// All objects need to be instantiated before this setjmp call so that |
// they will be cleaned up properly if an error occurs. |
if (setjmp(errorManager.fJmpBuf)) { |
- return return_false(cinfo, 0, 0, "setjmp YUV8"); |
+ return return_false(cinfo, "setjmp YUV8"); |
} |
initialize_info(&cinfo, &srcManager); |
@@ -925,7 +947,7 @@ bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentS |
int status = jpeg_read_header(&cinfo, true); |
if (status != JPEG_HEADER_OK) { |
- return return_false(cinfo, 0, 0, "read_header YUV8"); |
+ return return_false(cinfo, "read_header YUV8"); |
} |
if (cinfo.jpeg_color_space != JCS_YCbCr) { |
@@ -957,11 +979,11 @@ bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentS |
jpeg_start_decompress(), and then read output_width and output_height. |
*/ |
if (!jpeg_start_decompress(&cinfo)) { |
- return return_false(cinfo, 0, 0, "start_decompress YUV8"); |
+ return return_false(cinfo, "start_decompress YUV8"); |
} |
if (!output_raw_data(cinfo, planes, rowBytes)) { |
- return return_false(cinfo, 0, 0, "output_raw_data"); |
+ return return_false(cinfo, "output_raw_data"); |
} |
update_components_sizes(cinfo, componentSizes, kActualSize_SizeType); |
@@ -974,6 +996,8 @@ bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentS |
return true; |
} |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
#ifdef SK_BUILD_FOR_ANDROID |
bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) { |