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

Side by Side Diff: Source/core/platform/image-decoders/gif/GIFImageReader.cpp

Issue 23646005: Improve GIF decoding performance (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 3 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
OLDNEW
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK ***** 2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * 4 *
5 * The contents of this file are subject to the Mozilla Public License Version 5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with 6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at 7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/ 8 * http://www.mozilla.org/MPL/
9 * 9 *
10 * Software distributed under the License is distributed on an "AS IS" basis, 10 * Software distributed under the License is distributed on an "AS IS" basis,
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 #define GETN(n, s) \ 91 #define GETN(n, s) \
92 do { \ 92 do { \
93 m_bytesToConsume = (n); \ 93 m_bytesToConsume = (n); \
94 m_state = (s); \ 94 m_state = (s); \
95 } while (0) 95 } while (0)
96 96
97 // Get a 16-bit value stored in little-endian format. 97 // Get a 16-bit value stored in little-endian format.
98 #define GETINT16(p) ((p)[1]<<8|(p)[0]) 98 #define GETINT16(p) ((p)[1]<<8|(p)[0])
99 99
100 // Send the data to the display front-end. 100 // Send the data to the display front-end.
101 bool GIFLZWContext::outputRow() 101 bool GIFLZWContext::outputRow(GIFRow::const_iterator rowBegin)
102 { 102 {
103 int drowStart = irow; 103 int drowStart = irow;
104 int drowEnd = irow; 104 int drowEnd = irow;
105 105
106 // Haeberli-inspired hack for interlaced GIFs: Replicate lines while 106 // Haeberli-inspired hack for interlaced GIFs: Replicate lines while
107 // displaying to diminish the "venetian-blind" effect as the image is 107 // displaying to diminish the "venetian-blind" effect as the image is
108 // loaded. Adjust pixel vertical positions to avoid the appearance of the 108 // loaded. Adjust pixel vertical positions to avoid the appearance of the
109 // image crawling up the screen as successive passes are drawn. 109 // image crawling up the screen as successive passes are drawn.
110 if (m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass < 4) { 110 if (m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass < 4) {
111 unsigned rowDup = 0; 111 unsigned rowDup = 0;
(...skipping 29 matching lines...) Expand all
141 141
142 if ((unsigned)drowEnd >= m_frameContext->height()) 142 if ((unsigned)drowEnd >= m_frameContext->height())
143 drowEnd = m_frameContext->height() - 1; 143 drowEnd = m_frameContext->height() - 1;
144 } 144 }
145 145
146 // Protect against too much image data. 146 // Protect against too much image data.
147 if ((unsigned)drowStart >= m_frameContext->height()) 147 if ((unsigned)drowStart >= m_frameContext->height())
148 return true; 148 return true;
149 149
150 // CALLBACK: Let the client know we have decoded a row. 150 // CALLBACK: Let the client know we have decoded a row.
151 if (!m_client->haveDecodedRow(m_frameContext->frameId(), rowBuffer, m_frameC ontext->width(), 151 if (!m_client->haveDecodedRow(m_frameContext->frameId(), rowBegin, m_frameCo ntext->width(),
152 drowStart, drowEnd - drowStart + 1, m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass > 1)) 152 drowStart, drowEnd - drowStart + 1, m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass > 1))
153 return false; 153 return false;
154 154
155 if (!m_frameContext->interlaced()) 155 if (!m_frameContext->interlaced())
156 irow++; 156 irow++;
157 else { 157 else {
158 do { 158 do {
159 switch (ipass) { 159 switch (ipass) {
160 case 1: 160 case 1:
161 irow += 8; 161 irow += 8;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 } while (irow > (m_frameContext->height() - 1)); 195 } while (irow > (m_frameContext->height() - 1));
196 } 196 }
197 return true; 197 return true;
198 } 198 }
199 199
200 // Perform Lempel-Ziv-Welch decoding. 200 // Perform Lempel-Ziv-Welch decoding.
201 // Returns true if decoding was successful. In this case the block will have bee n completely consumed and/or rowsRemaining will be 0. 201 // Returns true if decoding was successful. In this case the block will have bee n completely consumed and/or rowsRemaining will be 0.
202 // Otherwise, decoding failed; returns false in this case, which will always cau se the GIFImageReader to set the "decode failed" flag. 202 // Otherwise, decoding failed; returns false in this case, which will always cau se the GIFImageReader to set the "decode failed" flag.
203 bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock) 203 bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock)
204 { 204 {
205 int code; 205 int code;
Peter Kasting 2013/08/29 23:46:25 Nit: Declare these first three where they are firs
Alpha Left Google 2013/08/30 23:25:36 Done.
206 int incode; 206 int incode;
207 const unsigned char *ch; 207 const unsigned char *ch;
208 size_t width = m_frameContext->width();
208 209
209 if (rowIter == rowBuffer.end()) 210 if (rowIter == rowBuffer.end())
210 return true; 211 return true;
211 212
212 #define OUTPUT_ROW \
213 do { \
214 if (!outputRow()) \
215 return false; \
216 rowsRemaining--; \
217 rowIter = rowBuffer.begin(); \
218 if (!rowsRemaining) \
219 return true; \
220 } while (0)
221
222 for (ch = block; bytesInBlock-- > 0; ch++) { 213 for (ch = block; bytesInBlock-- > 0; ch++) {
223 // Feed the next byte into the decoder's 32-bit input buffer. 214 // Feed the next byte into the decoder's 32-bit input buffer.
224 datum += ((int) *ch) << bits; 215 datum += ((int) *ch) << bits;
225 bits += 8; 216 bits += 8;
226 217
227 // Check for underflow of decoder's 32-bit input buffer. 218 // Check for underflow of decoder's 32-bit input buffer.
228 while (bits >= codesize) { 219 while (bits >= codesize) {
229 // Get the leading variable-length symbol from the data stream. 220 // Get the leading variable-length symbol from the data stream.
230 code = datum & codemask; 221 code = datum & codemask;
231 datum >>= codesize; 222 datum >>= codesize;
(...skipping 10 matching lines...) Expand all
242 233
243 // Check for explicit end-of-stream code. 234 // Check for explicit end-of-stream code.
244 if (code == (clearCode + 1)) { 235 if (code == (clearCode + 1)) {
245 // end-of-stream should only appear after all image data. 236 // end-of-stream should only appear after all image data.
246 if (!rowsRemaining) 237 if (!rowsRemaining)
247 return true; 238 return true;
248 return false; 239 return false;
249 } 240 }
250 241
251 if (oldcode == -1) { 242 if (oldcode == -1) {
243 // The previous code is not available either because this is the first
Peter Kasting 2013/08/29 23:46:25 Tiny nit: It seems like your comments in this sect
Alpha Left Google 2013/08/30 23:25:36 Done.
244 // code in the stream or the dictionary was reset. We'll write t he
245 // current code to stream. The code will have only one character .
Peter Kasting 2013/08/29 23:46:25 Nit: Maybe better second sentence: This code must
Alpha Left Google 2013/08/30 23:25:36 Done.
246 firstchar = oldcode = code;
247 if (rowIter >= rowBuffer.end())
248 return false;
252 *rowIter++ = suffix[code]; 249 *rowIter++ = suffix[code];
253 if (rowIter == rowBuffer.end()) 250 } else {
254 OUTPUT_ROW; 251 incode = code;
252 unsigned short codeLength = 0;
253 if (code < avail) {
254 // This is a complete code. Code length and code content are known.
Peter Kasting 2013/08/29 23:46:25 Nit: How about just: This is a pre-existing code,
Alpha Left Google 2013/08/30 23:25:36 Done.
255 codeLength = suffixLength[code];
256 rowIter += codeLength;
257 if (rowIter >= rowBuffer.end())
Peter Kasting 2013/08/29 23:46:25 Shouldn't this be '>', not ">=", since the row ite
Alpha Left Google 2013/08/30 23:25:36 Done.
258 return false;
259 } else if (code == avail) {
260 // This is an incomplete code. Code length is the length of previous
261 // code plus one. Code content is that of previous code conc atenated
262 // by the first character of previous code.
Peter Kasting 2013/08/29 23:46:25 Nit: How about: This is a new code just being add
Alpha Left Google 2013/08/30 23:25:36 Done.
263 codeLength = suffixLength[oldcode] + 1;
264 rowIter += codeLength;
265 if (rowIter >= rowBuffer.end())
266 return false;
255 267
256 firstchar = oldcode = code; 268 // The last character of this code is the first character of the
257 continue; 269 // previous code. Write it to output and then write the prev ious code.
Peter Kasting 2013/08/29 23:46:25 Nit: This comment seems unnecessary given the abov
Alpha Left Google 2013/08/30 23:25:36 Done.
270 *--rowIter = firstchar;
271 code = oldcode;
272 } else {
273 // Bad code received. Complete and incomplete codes are defi ned up
274 // to |avail|.
Peter Kasting 2013/08/29 23:46:25 Nit: How about just: This is an invalid code.
Alpha Left Google 2013/08/30 23:25:36 Done.
275 return false;
276 }
277
278 while (code >= clearCode) {
279 if (code >= MAX_BYTES || code == prefix[code])
Peter Kasting 2013/08/29 23:46:25 |code| must be less than MAX_BYTES, given how it w
Alpha Left Google 2013/08/30 23:25:36 I removed this block of comments entirely. Having
280 return false;
281
282 // Even though suffix[] only holds characters through suffix [avail - 1],
283 // allowing code >= avail here lets us be more tolerant of m alformed
284 // data. As long as code < MAX_BYTES, the only risk is a gar bled image,
285 // which is no worse than refusing to display it.
286 *--rowIter = suffix[code];
287 code = prefix[code];
288 }
289
290 *--rowIter = firstchar = suffix[code];
291
292 // Define a new codeword in the dictionary.
293 if (avail < 4096) {
Peter Kasting 2013/08/29 23:46:25 Nit: Use MAX_DICTIONARY_ENTRIES here in place of 4
Alpha Left Google 2013/08/30 23:25:36 Done.
294 prefix[avail] = oldcode;
295 suffix[avail] = firstchar;
296 suffixLength[avail] = suffixLength[oldcode] + 1;
297 avail++;
Peter Kasting 2013/08/29 23:46:25 Nit: I suggest using preincrement form wherever po
Alpha Left Google 2013/08/30 23:25:36 Done.
298
299 // If we've used up all the codewords of a given length
300 // increase the length of codewords by one bit, but don't
301 // exceed the specified maximum codeword size of 12 bits.
Peter Kasting 2013/08/29 23:46:25 Nit: Remove "of 12 bits". Here and elsewhere, I'd
Alpha Left Google 2013/08/30 23:25:36 Done.
302 if ((!(avail & codemask)) && (avail < 4096)) {
Peter Kasting 2013/08/29 23:46:25 Nit: Instead of "(avail < 4096)", the equivalent "
Alpha Left Google 2013/08/30 23:25:36 Done.
303 codesize++;
304 codemask += avail;
305 }
306 }
307 oldcode = incode;
308 rowIter += codeLength;
258 } 309 }
259 310
260 incode = code; 311 // Not enough bytes to output row.
261 if (code >= avail) { 312 if (rowIter < rowBuffer.begin() + width)
262 stack[stackp++] = firstchar; 313 continue;
Peter Kasting 2013/08/29 23:46:25 Nit: It seems slightly clearer to me to skip this,
Alpha Left Google 2013/08/30 23:25:36 Done.
263 code = oldcode;
264 314
265 if (stackp == MAX_BYTES) 315 // There's enough data to output. Output as many rows as possible.
316 GIFRow::iterator rowBegin = rowBuffer.begin();
317 for (;rowBegin + width <= rowIter; rowBegin += width) {
Peter Kasting 2013/08/29 23:46:25 Nit: Space after first semicolon. If you don't ta
Alpha Left Google 2013/08/30 23:25:36 Done.
318 if (!outputRow(rowBegin))
266 return false; 319 return false;
320 rowsRemaining--;
321 if (!rowsRemaining)
322 return true;
267 } 323 }
268 324
269 while (code >= clearCode) { 325 // These bytes cannot make up a full row. Move them to the beginning
270 if (code >= MAX_BYTES || code == prefix[code]) 326 // of buffer.
Peter Kasting 2013/08/29 23:46:25 Nit: How about just: Move the remaining bytes to
Alpha Left Google 2013/08/30 23:25:36 Done.
271 return false; 327 size_t bytesToCopy = rowIter - rowBegin;
272 328 memcpy(rowBuffer.begin(), rowBegin, bytesToCopy);
273 // Even though suffix[] only holds characters through suffix[ava il - 1], 329 rowIter = rowBuffer.begin() + bytesToCopy;
274 // allowing code >= avail here lets us be more tolerant of malfo rmed
275 // data. As long as code < MAX_BYTES, the only risk is a garbled image,
276 // which is no worse than refusing to display it.
277 stack[stackp++] = suffix[code];
278 code = prefix[code];
279
280 if (stackp == MAX_BYTES)
281 return false;
282 }
283
284 stack[stackp++] = firstchar = suffix[code];
285
286 // Define a new codeword in the dictionary.
287 if (avail < 4096) {
288 prefix[avail] = oldcode;
289 suffix[avail] = firstchar;
290 avail++;
291
292 // If we've used up all the codewords of a given length
293 // increase the length of codewords by one bit, but don't
294 // exceed the specified maximum codeword size of 12 bits.
295 if ((!(avail & codemask)) && (avail < 4096)) {
296 codesize++;
297 codemask += avail;
298 }
299 }
300 oldcode = incode;
301
302 // Copy the decoded data out to the scanline buffer.
303 do {
304 *rowIter++ = stack[--stackp];
305 if (rowIter == rowBuffer.end())
306 OUTPUT_ROW;
307 } while (stackp > 0);
308 } 330 }
309 } 331 }
310
311 return true; 332 return true;
312 } 333 }
313 334
314 void GIFColorMap::buildTable(const unsigned char* data, size_t length) 335 void GIFColorMap::buildTable(const unsigned char* data, size_t length)
315 { 336 {
316 if (!m_isDefined || !m_table.isEmpty()) 337 if (!m_isDefined || !m_table.isEmpty())
317 return; 338 return;
318 339
319 RELEASE_ASSERT(m_position + m_colors * GIF_COLORS <= length); 340 RELEASE_ASSERT(m_position + m_colors * GIF_COLORS <= length);
320 const unsigned char* srcColormap = data + m_position; 341 const unsigned char* srcColormap = data + m_position;
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
752 m_frames.append(adoptPtr(new GIFFrameContext(m_frames.size()))); 773 m_frames.append(adoptPtr(new GIFFrameContext(m_frames.size())));
753 } 774 }
754 775
755 // FIXME: Move this method to close to doLZW(). 776 // FIXME: Move this method to close to doLZW().
756 bool GIFLZWContext::prepareToDecode() 777 bool GIFLZWContext::prepareToDecode()
757 { 778 {
758 ASSERT(m_frameContext->isDataSizeDefined() && m_frameContext->isHeaderDefine d()); 779 ASSERT(m_frameContext->isDataSizeDefined() && m_frameContext->isHeaderDefine d());
759 780
760 // Since we use a codesize of 1 more than the datasize, we need to ensure 781 // Since we use a codesize of 1 more than the datasize, we need to ensure
761 // that our datasize is strictly less than the MAX_LZW_BITS value (12). 782 // that our datasize is strictly less than the MAX_LZW_BITS value (12).
762 // This sets the largest possible codemask correctly at 4095. 783 // This sets the largest possible codemask correctly at 4095.
Peter Kasting 2013/08/29 23:46:25 Nit: Remove last sentence, and remove "(12)" from
Alpha Left Google 2013/08/30 23:25:36 Done.
763 if (m_frameContext->dataSize() >= MAX_LZW_BITS) 784 if (m_frameContext->dataSize() >= MAX_LZW_BITS)
764 return false; 785 return false;
765 clearCode = 1 << m_frameContext->dataSize(); 786 clearCode = 1 << m_frameContext->dataSize();
766 if (clearCode >= MAX_BYTES) 787 if (clearCode >= MAX_BYTES)
Peter Kasting 2013/08/29 23:46:25 This conditional cannot fail given the previous co
Alpha Left Google 2013/08/30 23:25:36 Done.
767 return false; 788 return false;
768 789
769 avail = clearCode + 2; 790 avail = clearCode + 2;
770 oldcode = -1; 791 oldcode = -1;
771 codesize = m_frameContext->dataSize() + 1; 792 codesize = m_frameContext->dataSize() + 1;
772 codemask = (1 << codesize) - 1; 793 codemask = (1 << codesize) - 1;
773 datum = bits = 0; 794 datum = bits = 0;
774 ipass = m_frameContext->interlaced() ? 1 : 0; 795 ipass = m_frameContext->interlaced() ? 1 : 0;
775 irow = 0; 796 irow = 0;
776 797
777 // Initialize output row buffer. 798 // Initialize output row buffer.
778 rowBuffer.resize(m_frameContext->width()); 799 rowBuffer.resize(m_frameContext->width() + MAX_BYTES);
Peter Kasting 2013/08/29 23:46:25 (See my comment atop GIFImageReader.h as to why I
Alpha Left Google 2013/08/30 23:25:36 Done.
779 rowIter = rowBuffer.begin(); 800 rowIter = rowBuffer.begin();
780 rowsRemaining = m_frameContext->height(); 801 rowsRemaining = m_frameContext->height();
781 802
782 // Clearing the whole suffix table lets us be more tolerant of bad data. 803 // Clearing the whole suffix table lets us be more tolerant of bad data.
783 memset(suffix, 0, sizeof(suffix)); 804 memset(suffix, 0, sizeof(suffix));
Peter Kasting 2013/08/29 23:46:25 Nit: Seems like we could save a little time on the
Alpha Left Google 2013/08/30 23:25:36 Done.
805 for (int i = 0; i < clearCode; ++i)
806 suffix[i] = i;
807 for (int i = 0; i < MAX_BYTES; i++)
808 suffixLength[i] = 1;
784 809
785 // Clearing the whole prefix table to prevent uninitialized access. 810 // Clearing the whole prefix table to prevent uninitialized access.
786 memset(prefix, 0, sizeof(prefix)); 811 memset(prefix, 0, sizeof(prefix));
787 for (int i = 0; i < clearCode; i++)
788 suffix[i] = i;
789 stackp = 0;
790 return true; 812 return true;
791 } 813 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698