Fix failure exits from JPEG onBuildTileIndex.
The setjmp exited without deleting the SkJPEGImageIndex, and another exit condition deleted the huffman index even though it had not been created yet. Create member functions on SkJPEGImageIndex to make the jpeg calls so it can keep track of what has been created, and avoid destroying anything else. Remove unnecessary lines to set values to their default values. Move all SkJPEGImageIndex code entirely inside #ifdef ANDROID blocks, since no piece of it is used except by ANDROID only code. BUG=skia:1471 R=djsollen@google.com, mtklein@google.com Review URL: https://codereview.chromium.org/21891007 git-svn-id: http://skia.googlecode.com/svn/trunk@10628 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
2fe638ef06
commit
a1a515474d
@ -55,45 +55,115 @@ static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) {
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
class SkJPEGImageIndex {
|
class SkJPEGImageIndex {
|
||||||
public:
|
public:
|
||||||
SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder)
|
SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder)
|
||||||
: fSrcMgr(stream, decoder) {}
|
: fSrcMgr(stream, decoder)
|
||||||
|
, fInfoInitialized(false)
|
||||||
|
, fHuffmanCreated(false)
|
||||||
|
, fDecompressStarted(false)
|
||||||
|
{
|
||||||
|
SkDEBUGCODE(fReadHeaderSucceeded = false;)
|
||||||
|
}
|
||||||
|
|
||||||
~SkJPEGImageIndex() {
|
~SkJPEGImageIndex() {
|
||||||
#ifdef SK_BUILD_FOR_ANDROID
|
if (fHuffmanCreated) {
|
||||||
jpeg_destroy_huffman_index(&fHuffmanIndex);
|
fHuffmanCreated = false;
|
||||||
#endif
|
jpeg_destroy_huffman_index(&fHuffmanIndex);
|
||||||
jpeg_finish_decompress(&fCInfo);
|
}
|
||||||
jpeg_destroy_decompress(&fCInfo);
|
if (fDecompressStarted) {
|
||||||
|
fDecompressStarted = false;
|
||||||
|
jpeg_finish_decompress(&fCInfo);
|
||||||
|
}
|
||||||
|
if (fInfoInitialized) {
|
||||||
|
this->destroyInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init the cinfo struct using libjpeg and apply any necessary
|
* Destroy the cinfo struct.
|
||||||
* customizations.
|
* After this call, if a huffman index was already built, it
|
||||||
|
* can be used after calling initializeInfoAndReadHeader
|
||||||
|
* again. Must not be called after startTileDecompress except
|
||||||
|
* in the destructor.
|
||||||
*/
|
*/
|
||||||
void initializeInfo() {
|
void destroyInfo() {
|
||||||
|
SkASSERT(fInfoInitialized);
|
||||||
|
SkASSERT(!fDecompressStarted);
|
||||||
|
fInfoInitialized = false;
|
||||||
|
jpeg_destroy_decompress(&fCInfo);
|
||||||
|
SkDEBUGCODE(fReadHeaderSucceeded = false;)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the cinfo struct.
|
||||||
|
* Calls jpeg_create_decompress, makes customizations, and
|
||||||
|
* finally calls jpeg_read_header. Returns true if jpeg_read_header
|
||||||
|
* returns JPEG_HEADER_OK.
|
||||||
|
* If cinfo was already initialized, destroyInfo must be called to
|
||||||
|
* destroy the old one. Must not be called after startTileDecompress.
|
||||||
|
*/
|
||||||
|
bool initializeInfoAndReadHeader() {
|
||||||
|
SkASSERT(!fInfoInitialized && !fDecompressStarted);
|
||||||
jpeg_create_decompress(&fCInfo);
|
jpeg_create_decompress(&fCInfo);
|
||||||
overwrite_mem_buffer_size(&fCInfo);
|
overwrite_mem_buffer_size(&fCInfo);
|
||||||
fCInfo.src = &fSrcMgr;
|
fCInfo.src = &fSrcMgr;
|
||||||
|
fInfoInitialized = true;
|
||||||
|
const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true));
|
||||||
|
SkDEBUGCODE(fReadHeaderSucceeded = success;)
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg_decompress_struct* cinfo() { return &fCInfo; }
|
jpeg_decompress_struct* cinfo() { return &fCInfo; }
|
||||||
|
|
||||||
#ifdef SK_BUILD_FOR_ANDROID
|
|
||||||
huffman_index* huffmanIndex() { return &fHuffmanIndex; }
|
huffman_index* huffmanIndex() { return &fHuffmanIndex; }
|
||||||
#endif
|
|
||||||
|
/**
|
||||||
|
* Build the index to be used for tile based decoding.
|
||||||
|
* Must only be called after a successful call to
|
||||||
|
* initializeInfoAndReadHeader and must not be called more
|
||||||
|
* than once.
|
||||||
|
*/
|
||||||
|
bool buildHuffmanIndex() {
|
||||||
|
SkASSERT(fReadHeaderSucceeded);
|
||||||
|
SkASSERT(!fHuffmanCreated);
|
||||||
|
jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex);
|
||||||
|
fHuffmanCreated = true;
|
||||||
|
SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom);
|
||||||
|
return jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start tile based decoding. Must only be called after a
|
||||||
|
* successful call to buildHuffmanIndex, and must only be
|
||||||
|
* called once.
|
||||||
|
*/
|
||||||
|
bool startTileDecompress() {
|
||||||
|
SkASSERT(fHuffmanCreated);
|
||||||
|
SkASSERT(fReadHeaderSucceeded);
|
||||||
|
SkASSERT(!fDecompressStarted);
|
||||||
|
if (jpeg_start_tile_decompress(&fCInfo)) {
|
||||||
|
fDecompressStarted = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
skjpeg_source_mgr fSrcMgr;
|
skjpeg_source_mgr fSrcMgr;
|
||||||
jpeg_decompress_struct fCInfo;
|
jpeg_decompress_struct fCInfo;
|
||||||
#ifdef SK_BUILD_FOR_ANDROID
|
|
||||||
huffman_index fHuffmanIndex;
|
huffman_index fHuffmanIndex;
|
||||||
#endif
|
bool fInfoInitialized;
|
||||||
|
bool fHuffmanCreated;
|
||||||
|
bool fDecompressStarted;
|
||||||
|
SkDEBUGCODE(bool fReadHeaderSucceeded;)
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
class SkJPEGImageDecoder : public SkImageDecoder {
|
class SkJPEGImageDecoder : public SkImageDecoder {
|
||||||
public:
|
public:
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
SkJPEGImageDecoder() {
|
SkJPEGImageDecoder() {
|
||||||
fImageIndex = NULL;
|
fImageIndex = NULL;
|
||||||
fImageWidth = 0;
|
fImageWidth = 0;
|
||||||
@ -103,6 +173,7 @@ public:
|
|||||||
virtual ~SkJPEGImageDecoder() {
|
virtual ~SkJPEGImageDecoder() {
|
||||||
SkDELETE(fImageIndex);
|
SkDELETE(fImageIndex);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
virtual Format getFormat() const {
|
virtual Format getFormat() const {
|
||||||
return kJPEG_Format;
|
return kJPEG_Format;
|
||||||
@ -116,9 +187,11 @@ protected:
|
|||||||
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
|
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
SkJPEGImageIndex* fImageIndex;
|
SkJPEGImageIndex* fImageIndex;
|
||||||
int fImageWidth;
|
int fImageWidth;
|
||||||
int fImageHeight;
|
int fImageHeight;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef SkImageDecoder INHERITED;
|
typedef SkImageDecoder INHERITED;
|
||||||
};
|
};
|
||||||
@ -475,9 +548,8 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
|
|||||||
#ifdef SK_BUILD_FOR_ANDROID
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *height) {
|
bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *height) {
|
||||||
|
|
||||||
SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this));
|
SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this)));
|
||||||
jpeg_decompress_struct* cinfo = imageIndex->cinfo();
|
jpeg_decompress_struct* cinfo = imageIndex->cinfo();
|
||||||
huffman_index* huffmanIndex = imageIndex->huffmanIndex();
|
|
||||||
|
|
||||||
skjpeg_error_mgr sk_err;
|
skjpeg_error_mgr sk_err;
|
||||||
cinfo->err = jpeg_std_error(&sk_err);
|
cinfo->err = jpeg_std_error(&sk_err);
|
||||||
@ -490,33 +562,19 @@ bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the cinfo used to create/build the huffmanIndex
|
// create the cinfo used to create/build the huffmanIndex
|
||||||
imageIndex->initializeInfo();
|
if (!imageIndex->initializeInfoAndReadHeader()) {
|
||||||
cinfo->do_fancy_upsampling = 0;
|
|
||||||
cinfo->do_block_smoothing = 0;
|
|
||||||
|
|
||||||
int status = jpeg_read_header(cinfo, true);
|
|
||||||
if (JPEG_HEADER_OK != status) {
|
|
||||||
SkDELETE(imageIndex);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg_create_huffman_index(cinfo, huffmanIndex);
|
if (!imageIndex->buildHuffmanIndex()) {
|
||||||
cinfo->scale_num = 1;
|
|
||||||
cinfo->scale_denom = 1;
|
|
||||||
if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) {
|
|
||||||
SkDELETE(imageIndex);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// destroy the cinfo used to create/build the huffman index
|
// destroy the cinfo used to create/build the huffman index
|
||||||
jpeg_destroy_decompress(cinfo);
|
imageIndex->destroyInfo();
|
||||||
|
|
||||||
// Init decoder to image decode mode
|
// Init decoder to image decode mode
|
||||||
imageIndex->initializeInfo();
|
if (!imageIndex->initializeInfoAndReadHeader()) {
|
||||||
|
|
||||||
status = jpeg_read_header(cinfo, true);
|
|
||||||
if (JPEG_HEADER_OK != status) {
|
|
||||||
SkDELETE(imageIndex);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,16 +583,18 @@ bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei
|
|||||||
cinfo->do_block_smoothing = 0;
|
cinfo->do_block_smoothing = 0;
|
||||||
|
|
||||||
// instead of jpeg_start_decompress() we start a tiled decompress
|
// instead of jpeg_start_decompress() we start a tiled decompress
|
||||||
jpeg_start_tile_decompress(cinfo);
|
if (!imageIndex->startTileDecompress()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cinfo->scale_num = 1;
|
SkASSERT(1 == cinfo->scale_num);
|
||||||
*height = cinfo->output_height;
|
*height = cinfo->output_height;
|
||||||
*width = cinfo->output_width;
|
*width = cinfo->output_width;
|
||||||
fImageWidth = *width;
|
fImageWidth = *width;
|
||||||
fImageHeight = *height;
|
fImageHeight = *height;
|
||||||
|
|
||||||
SkDELETE(fImageIndex);
|
SkDELETE(fImageIndex);
|
||||||
fImageIndex = imageIndex;
|
fImageIndex = imageIndex.detach();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user