 Chromium Code Reviews
 Chromium Code Reviews Issue 21891007:
  Fix failure exits from JPEG onBuildTileIndex.  (Closed) 
  Base URL: https://skia.googlecode.com/svn/trunk
    
  
    Issue 21891007:
  Fix failure exits from JPEG onBuildTileIndex.  (Closed) 
  Base URL: https://skia.googlecode.com/svn/trunk| Index: src/images/SkImageDecoder_libjpeg.cpp | 
| diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp | 
| index d4047f197356a15b09bb02cd2a36089caf0d6df8..914ceb7e8aa458a3ea4e011be2db27f73d0ead8a 100644 | 
| --- a/src/images/SkImageDecoder_libjpeg.cpp | 
| +++ b/src/images/SkImageDecoder_libjpeg.cpp | 
| @@ -55,45 +55,115 @@ static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) { | 
| ////////////////////////////////////////////////////////////////////////// | 
| ////////////////////////////////////////////////////////////////////////// | 
| +#ifdef SK_BUILD_FOR_ANDROID | 
| class SkJPEGImageIndex { | 
| public: | 
| SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) | 
| - : fSrcMgr(stream, decoder) {} | 
| + : fSrcMgr(stream, decoder) | 
| + , fInfoInitialized(false) | 
| + , fHuffmanCreated(false) | 
| + , fDecompressStarted(false) | 
| + { | 
| + SkDEBUGCODE(fReadHeaderSucceeded = false;) | 
| + } | 
| ~SkJPEGImageIndex() { | 
| -#ifdef SK_BUILD_FOR_ANDROID | 
| - jpeg_destroy_huffman_index(&fHuffmanIndex); | 
| -#endif | 
| - jpeg_finish_decompress(&fCInfo); | 
| + if (fHuffmanCreated) { | 
| + fHuffmanCreated = false; | 
| + jpeg_destroy_huffman_index(&fHuffmanIndex); | 
| + } | 
| + if (fDecompressStarted) { | 
| + fDecompressStarted = false; | 
| 
scroggo
2013/08/05 15:18:41
As mtklein pointed out, in patch set 3, if jpeg_fi
 | 
| + jpeg_finish_decompress(&fCInfo); | 
| + } | 
| + if (fInfoInitialized) { | 
| + this->destroyInfo(); | 
| + } | 
| + } | 
| + | 
| + /** | 
| + * Destroy the cinfo struct. | 
| + * 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 destroyInfo() { | 
| + SkASSERT(fInfoInitialized); | 
| + SkASSERT(!fDecompressStarted); | 
| + fInfoInitialized = false; | 
| jpeg_destroy_decompress(&fCInfo); | 
| + SkDEBUGCODE(fReadHeaderSucceeded = false;) | 
| } | 
| /** | 
| - * Init the cinfo struct using libjpeg and apply any necessary | 
| - * customizations. | 
| + * 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. | 
| */ | 
| - void initializeInfo() { | 
| + bool initializeInfoAndReadHeader() { | 
| + SkASSERT(!fInfoInitialized && !fDecompressStarted); | 
| jpeg_create_decompress(&fCInfo); | 
| overwrite_mem_buffer_size(&fCInfo); | 
| 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; } | 
| -#ifdef SK_BUILD_FOR_ANDROID | 
| 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: | 
| skjpeg_source_mgr fSrcMgr; | 
| jpeg_decompress_struct fCInfo; | 
| -#ifdef SK_BUILD_FOR_ANDROID | 
| huffman_index fHuffmanIndex; | 
| -#endif | 
| + bool fInfoInitialized; | 
| + bool fHuffmanCreated; | 
| + bool fDecompressStarted; | 
| + SkDEBUGCODE(bool fReadHeaderSucceeded;) | 
| }; | 
| +#endif | 
| class SkJPEGImageDecoder : public SkImageDecoder { | 
| public: | 
| +#ifdef SK_BUILD_FOR_ANDROID | 
| SkJPEGImageDecoder() { | 
| fImageIndex = NULL; | 
| fImageWidth = 0; | 
| @@ -103,6 +173,7 @@ public: | 
| virtual ~SkJPEGImageDecoder() { | 
| SkDELETE(fImageIndex); | 
| } | 
| +#endif | 
| virtual Format getFormat() const { | 
| return kJPEG_Format; | 
| @@ -116,9 +187,11 @@ protected: | 
| virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 
| private: | 
| +#ifdef SK_BUILD_FOR_ANDROID | 
| SkJPEGImageIndex* fImageIndex; | 
| int fImageWidth; | 
| int fImageHeight; | 
| +#endif | 
| typedef SkImageDecoder INHERITED; | 
| }; | 
| @@ -475,9 +548,8 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { | 
| #ifdef SK_BUILD_FOR_ANDROID | 
| 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(); | 
| - huffman_index* huffmanIndex = imageIndex->huffmanIndex(); | 
| skjpeg_error_mgr 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 | 
| - imageIndex->initializeInfo(); | 
| - cinfo->do_fancy_upsampling = 0; | 
| - cinfo->do_block_smoothing = 0; | 
| - | 
| - int status = jpeg_read_header(cinfo, true); | 
| - if (JPEG_HEADER_OK != status) { | 
| - SkDELETE(imageIndex); | 
| + if (!imageIndex->initializeInfoAndReadHeader()) { | 
| return false; | 
| } | 
| - jpeg_create_huffman_index(cinfo, huffmanIndex); | 
| - cinfo->scale_num = 1; | 
| - cinfo->scale_denom = 1; | 
| - if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) { | 
| - SkDELETE(imageIndex); | 
| + if (!imageIndex->buildHuffmanIndex()) { | 
| return false; | 
| } | 
| // destroy the cinfo used to create/build the huffman index | 
| - jpeg_destroy_decompress(cinfo); | 
| + imageIndex->destroyInfo(); | 
| // Init decoder to image decode mode | 
| - imageIndex->initializeInfo(); | 
| - | 
| - status = jpeg_read_header(cinfo, true); | 
| - if (JPEG_HEADER_OK != status) { | 
| - SkDELETE(imageIndex); | 
| + if (!imageIndex->initializeInfoAndReadHeader()) { | 
| return false; | 
| } | 
| @@ -525,16 +583,18 @@ bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei | 
| cinfo->do_block_smoothing = 0; | 
| // 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; | 
| *width = cinfo->output_width; | 
| fImageWidth = *width; | 
| fImageHeight = *height; | 
| SkDELETE(fImageIndex); | 
| - fImageIndex = imageIndex; | 
| + fImageIndex = imageIndex.detach(); | 
| return true; | 
| } |