Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(550)

Side by Side Diff: src/images/SkImageDecoder_libjpeg.cpp

Issue 21891007: Fix failure exits from JPEG onBuildTileIndex. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Set SkJPEGImageIndex state before calling jpeg functions. Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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);
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698