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; |
} |