 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| OLD | NEW | 
|---|---|
| 1 /* | 1 /* | 
| 2 * Copyright 2007 The Android Open Source Project | 2 * Copyright 2007 The Android Open Source Project | 
| 3 * | 3 * | 
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be | 
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. | 
| 6 */ | 6 */ | 
| 7 | 7 | 
| 8 | 8 | 
| 9 #include "SkImageDecoder.h" | 9 #include "SkImageDecoder.h" | 
| 10 #include "SkImageEncoder.h" | 10 #include "SkImageEncoder.h" | 
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 48 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; | 48 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; | 
| 49 #else | 49 #else | 
| 50 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; | 50 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; | 
| 51 #endif | 51 #endif | 
| 52 #endif // SK_BUILD_FOR_ANDROID | 52 #endif // SK_BUILD_FOR_ANDROID | 
| 53 } | 53 } | 
| 54 | 54 | 
| 55 ////////////////////////////////////////////////////////////////////////// | 55 ////////////////////////////////////////////////////////////////////////// | 
| 56 ////////////////////////////////////////////////////////////////////////// | 56 ////////////////////////////////////////////////////////////////////////// | 
| 57 | 57 | 
| 58 #ifdef SK_BUILD_FOR_ANDROID | |
| 58 class SkJPEGImageIndex { | 59 class SkJPEGImageIndex { | 
| 59 public: | 60 public: | 
| 60 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) | 61 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) | 
| 61 : fSrcMgr(stream, decoder) {} | 62 : fSrcMgr(stream, decoder) | 
| 63 , fInfoInitialized(false) | |
| 64 , fHuffmanCreated(false) | |
| 65 , fDecompressStarted(false) | |
| 66 { | |
| 67 SkDEBUGCODE(fReadHeaderSucceeded = false;) | |
| 68 } | |
| 62 | 69 | 
| 63 ~SkJPEGImageIndex() { | 70 ~SkJPEGImageIndex() { | 
| 64 #ifdef SK_BUILD_FOR_ANDROID | 71 if (fHuffmanCreated) { | 
| 65 jpeg_destroy_huffman_index(&fHuffmanIndex); | 72 fHuffmanCreated = false; | 
| 66 #endif | 73 jpeg_destroy_huffman_index(&fHuffmanIndex); | 
| 67 jpeg_finish_decompress(&fCInfo); | 74 } | 
| 68 jpeg_destroy_decompress(&fCInfo); | 75 if (fDecompressStarted) { | 
| 76 fDecompressStarted = false; | |
| 
scroggo
2013/08/05 15:18:41
As mtklein pointed out, in patch set 3, if jpeg_fi
 | |
| 77 jpeg_finish_decompress(&fCInfo); | |
| 78 } | |
| 79 if (fInfoInitialized) { | |
| 80 this->destroyInfo(); | |
| 81 } | |
| 69 } | 82 } | 
| 70 | 83 | 
| 71 /** | 84 /** | 
| 72 * Init the cinfo struct using libjpeg and apply any necessary | 85 * Destroy the cinfo struct. | 
| 73 * customizations. | 86 * After this call, if a huffman index was already built, it | 
| 87 * can be used after calling initializeInfoAndReadHeader | |
| 88 * again. Must not be called after startTileDecompress except | |
| 89 * in the destructor. | |
| 74 */ | 90 */ | 
| 75 void initializeInfo() { | 91 void destroyInfo() { | 
| 92 SkASSERT(fInfoInitialized); | |
| 93 SkASSERT(!fDecompressStarted); | |
| 94 fInfoInitialized = false; | |
| 95 jpeg_destroy_decompress(&fCInfo); | |
| 96 SkDEBUGCODE(fReadHeaderSucceeded = false;) | |
| 97 } | |
| 98 | |
| 99 /** | |
| 100 * Initialize the cinfo struct. | |
| 101 * Calls jpeg_create_decompress, makes customizations, and | |
| 102 * finally calls jpeg_read_header. Returns true if jpeg_read_header | |
| 103 * returns JPEG_HEADER_OK. | |
| 104 * If cinfo was already initialized, destroyInfo must be called to | |
| 105 * destroy the old one. Must not be called after startTileDecompress. | |
| 106 */ | |
| 107 bool initializeInfoAndReadHeader() { | |
| 108 SkASSERT(!fInfoInitialized && !fDecompressStarted); | |
| 76 jpeg_create_decompress(&fCInfo); | 109 jpeg_create_decompress(&fCInfo); | 
| 77 overwrite_mem_buffer_size(&fCInfo); | 110 overwrite_mem_buffer_size(&fCInfo); | 
| 78 fCInfo.src = &fSrcMgr; | 111 fCInfo.src = &fSrcMgr; | 
| 112 fInfoInitialized = true; | |
| 113 const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true)) ; | |
| 114 SkDEBUGCODE(fReadHeaderSucceeded = success;) | |
| 115 return success; | |
| 79 } | 116 } | 
| 80 | 117 | 
| 81 jpeg_decompress_struct* cinfo() { return &fCInfo; } | 118 jpeg_decompress_struct* cinfo() { return &fCInfo; } | 
| 82 | 119 | 
| 83 #ifdef SK_BUILD_FOR_ANDROID | |
| 84 huffman_index* huffmanIndex() { return &fHuffmanIndex; } | 120 huffman_index* huffmanIndex() { return &fHuffmanIndex; } | 
| 85 #endif | 121 | 
| 122 /** | |
| 123 * Build the index to be used for tile based decoding. | |
| 124 * Must only be called after a successful call to | |
| 125 * initializeInfoAndReadHeader and must not be called more | |
| 126 * than once. | |
| 127 */ | |
| 128 bool buildHuffmanIndex() { | |
| 129 SkASSERT(fReadHeaderSucceeded); | |
| 130 SkASSERT(!fHuffmanCreated); | |
| 131 jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex); | |
| 132 fHuffmanCreated = true; | |
| 133 SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom); | |
| 134 return jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex); | |
| 135 } | |
| 136 | |
| 137 /** | |
| 138 * Start tile based decoding. Must only be called after a | |
| 139 * successful call to buildHuffmanIndex, and must only be | |
| 140 * called once. | |
| 141 */ | |
| 142 bool startTileDecompress() { | |
| 143 SkASSERT(fHuffmanCreated); | |
| 144 SkASSERT(fReadHeaderSucceeded); | |
| 145 SkASSERT(!fDecompressStarted); | |
| 146 if (jpeg_start_tile_decompress(&fCInfo)) { | |
| 147 fDecompressStarted = true; | |
| 148 return true; | |
| 149 } | |
| 150 return false; | |
| 151 } | |
| 86 | 152 | 
| 87 private: | 153 private: | 
| 88 skjpeg_source_mgr fSrcMgr; | 154 skjpeg_source_mgr fSrcMgr; | 
| 89 jpeg_decompress_struct fCInfo; | 155 jpeg_decompress_struct fCInfo; | 
| 90 #ifdef SK_BUILD_FOR_ANDROID | |
| 91 huffman_index fHuffmanIndex; | 156 huffman_index fHuffmanIndex; | 
| 157 bool fInfoInitialized; | |
| 158 bool fHuffmanCreated; | |
| 159 bool fDecompressStarted; | |
| 160 SkDEBUGCODE(bool fReadHeaderSucceeded;) | |
| 161 }; | |
| 92 #endif | 162 #endif | 
| 93 }; | |
| 94 | 163 | 
| 95 class SkJPEGImageDecoder : public SkImageDecoder { | 164 class SkJPEGImageDecoder : public SkImageDecoder { | 
| 96 public: | 165 public: | 
| 166 #ifdef SK_BUILD_FOR_ANDROID | |
| 97 SkJPEGImageDecoder() { | 167 SkJPEGImageDecoder() { | 
| 98 fImageIndex = NULL; | 168 fImageIndex = NULL; | 
| 99 fImageWidth = 0; | 169 fImageWidth = 0; | 
| 100 fImageHeight = 0; | 170 fImageHeight = 0; | 
| 101 } | 171 } | 
| 102 | 172 | 
| 103 virtual ~SkJPEGImageDecoder() { | 173 virtual ~SkJPEGImageDecoder() { | 
| 104 SkDELETE(fImageIndex); | 174 SkDELETE(fImageIndex); | 
| 105 } | 175 } | 
| 176 #endif | |
| 106 | 177 | 
| 107 virtual Format getFormat() const { | 178 virtual Format getFormat() const { | 
| 108 return kJPEG_Format; | 179 return kJPEG_Format; | 
| 109 } | 180 } | 
| 110 | 181 | 
| 111 protected: | 182 protected: | 
| 112 #ifdef SK_BUILD_FOR_ANDROID | 183 #ifdef SK_BUILD_FOR_ANDROID | 
| 113 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_ OVERRIDE; | 184 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_ OVERRIDE; | 
| 114 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRI DE; | 185 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRI DE; | 
| 115 #endif | 186 #endif | 
| 116 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 187 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 
| 117 | 188 | 
| 118 private: | 189 private: | 
| 190 #ifdef SK_BUILD_FOR_ANDROID | |
| 119 SkJPEGImageIndex* fImageIndex; | 191 SkJPEGImageIndex* fImageIndex; | 
| 120 int fImageWidth; | 192 int fImageWidth; | 
| 121 int fImageHeight; | 193 int fImageHeight; | 
| 194 #endif | |
| 122 | 195 | 
| 123 typedef SkImageDecoder INHERITED; | 196 typedef SkImageDecoder INHERITED; | 
| 124 }; | 197 }; | 
| 125 | 198 | 
| 126 ////////////////////////////////////////////////////////////////////////// | 199 ////////////////////////////////////////////////////////////////////////// | 
| 127 | 200 | 
| 128 /* Automatically clean up after throwing an exception */ | 201 /* Automatically clean up after throwing an exception */ | 
| 129 class JPEGAutoClean { | 202 class JPEGAutoClean { | 
| 130 public: | 203 public: | 
| 131 JPEGAutoClean(): cinfo_ptr(NULL) {} | 204 JPEGAutoClean(): cinfo_ptr(NULL) {} | 
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 468 return return_false(cinfo, *bm, "skip rows"); | 541 return return_false(cinfo, *bm, "skip rows"); | 
| 469 } | 542 } | 
| 470 jpeg_finish_decompress(&cinfo); | 543 jpeg_finish_decompress(&cinfo); | 
| 471 | 544 | 
| 472 return true; | 545 return true; | 
| 473 } | 546 } | 
| 474 | 547 | 
| 475 #ifdef SK_BUILD_FOR_ANDROID | 548 #ifdef SK_BUILD_FOR_ANDROID | 
| 476 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei ght) { | 549 bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *hei ght) { | 
| 477 | 550 | 
| 478 SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this)); | 551 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (str eam, this))); | 
| 479 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); | 552 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); | 
| 480 huffman_index* huffmanIndex = imageIndex->huffmanIndex(); | |
| 481 | 553 | 
| 482 skjpeg_error_mgr sk_err; | 554 skjpeg_error_mgr sk_err; | 
| 483 cinfo->err = jpeg_std_error(&sk_err); | 555 cinfo->err = jpeg_std_error(&sk_err); | 
| 484 sk_err.error_exit = skjpeg_error_exit; | 556 sk_err.error_exit = skjpeg_error_exit; | 
| 485 | 557 | 
| 486 // All objects need to be instantiated before this setjmp call so that | 558 // All objects need to be instantiated before this setjmp call so that | 
| 487 // they will be cleaned up properly if an error occurs. | 559 // they will be cleaned up properly if an error occurs. | 
| 488 if (setjmp(sk_err.fJmpBuf)) { | 560 if (setjmp(sk_err.fJmpBuf)) { | 
| 489 return false; | 561 return false; | 
| 490 } | 562 } | 
| 491 | 563 | 
| 492 // create the cinfo used to create/build the huffmanIndex | 564 // create the cinfo used to create/build the huffmanIndex | 
| 493 imageIndex->initializeInfo(); | 565 if (!imageIndex->initializeInfoAndReadHeader()) { | 
| 494 cinfo->do_fancy_upsampling = 0; | |
| 495 cinfo->do_block_smoothing = 0; | |
| 496 | |
| 497 int status = jpeg_read_header(cinfo, true); | |
| 498 if (JPEG_HEADER_OK != status) { | |
| 499 SkDELETE(imageIndex); | |
| 500 return false; | 566 return false; | 
| 501 } | 567 } | 
| 502 | 568 | 
| 503 jpeg_create_huffman_index(cinfo, huffmanIndex); | 569 if (!imageIndex->buildHuffmanIndex()) { | 
| 504 cinfo->scale_num = 1; | |
| 505 cinfo->scale_denom = 1; | |
| 506 if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) { | |
| 507 SkDELETE(imageIndex); | |
| 508 return false; | 570 return false; | 
| 509 } | 571 } | 
| 510 | 572 | 
| 511 // destroy the cinfo used to create/build the huffman index | 573 // destroy the cinfo used to create/build the huffman index | 
| 512 jpeg_destroy_decompress(cinfo); | 574 imageIndex->destroyInfo(); | 
| 513 | 575 | 
| 514 // Init decoder to image decode mode | 576 // Init decoder to image decode mode | 
| 515 imageIndex->initializeInfo(); | 577 if (!imageIndex->initializeInfoAndReadHeader()) { | 
| 516 | |
| 517 status = jpeg_read_header(cinfo, true); | |
| 518 if (JPEG_HEADER_OK != status) { | |
| 519 SkDELETE(imageIndex); | |
| 520 return false; | 578 return false; | 
| 521 } | 579 } | 
| 522 | 580 | 
| 523 cinfo->out_color_space = JCS_RGBA_8888; | 581 cinfo->out_color_space = JCS_RGBA_8888; | 
| 524 cinfo->do_fancy_upsampling = 0; | 582 cinfo->do_fancy_upsampling = 0; | 
| 525 cinfo->do_block_smoothing = 0; | 583 cinfo->do_block_smoothing = 0; | 
| 526 | 584 | 
| 527 // instead of jpeg_start_decompress() we start a tiled decompress | 585 // instead of jpeg_start_decompress() we start a tiled decompress | 
| 528 jpeg_start_tile_decompress(cinfo); | 586 if (!imageIndex->startTileDecompress()) { | 
| 587 return false; | |
| 588 } | |
| 529 | 589 | 
| 530 cinfo->scale_num = 1; | 590 SkASSERT(1 == cinfo->scale_num); | 
| 531 *height = cinfo->output_height; | 591 *height = cinfo->output_height; | 
| 532 *width = cinfo->output_width; | 592 *width = cinfo->output_width; | 
| 533 fImageWidth = *width; | 593 fImageWidth = *width; | 
| 534 fImageHeight = *height; | 594 fImageHeight = *height; | 
| 535 | 595 | 
| 536 SkDELETE(fImageIndex); | 596 SkDELETE(fImageIndex); | 
| 537 fImageIndex = imageIndex; | 597 fImageIndex = imageIndex.detach(); | 
| 538 | 598 | 
| 539 return true; | 599 return true; | 
| 540 } | 600 } | 
| 541 | 601 | 
| 542 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 602 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 
| 543 if (NULL == fImageIndex) { | 603 if (NULL == fImageIndex) { | 
| 544 return false; | 604 return false; | 
| 545 } | 605 } | 
| 546 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); | 606 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); | 
| 547 | 607 | 
| (...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1015 } | 1075 } | 
| 1016 | 1076 | 
| 1017 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1077 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 
| 1018 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 1078 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; | 
| 1019 } | 1079 } | 
| 1020 | 1080 | 
| 1021 | 1081 | 
| 1022 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); | 1082 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); | 
| 1023 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg ); | 1083 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg ); | 
| 1024 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact ory); | 1084 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efact ory); | 
| OLD | NEW |