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

Unified 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, 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 side-by-side diff with in-line comments
Download patch
Index: Source/core/platform/image-decoders/gif/GIFImageReader.cpp
diff --git a/Source/core/platform/image-decoders/gif/GIFImageReader.cpp b/Source/core/platform/image-decoders/gif/GIFImageReader.cpp
index 7716cedef363aebbee4eca7cfb9af0389a219161..fba6228e96bdf38f5eafd74a39baf0602f225aff 100644
--- a/Source/core/platform/image-decoders/gif/GIFImageReader.cpp
+++ b/Source/core/platform/image-decoders/gif/GIFImageReader.cpp
@@ -98,7 +98,7 @@ using WebCore::GIFImageDecoder;
#define GETINT16(p) ((p)[1]<<8|(p)[0])
// Send the data to the display front-end.
-bool GIFLZWContext::outputRow()
+bool GIFLZWContext::outputRow(GIFRow::const_iterator rowBegin)
{
int drowStart = irow;
int drowEnd = irow;
@@ -148,7 +148,7 @@ bool GIFLZWContext::outputRow()
return true;
// CALLBACK: Let the client know we have decoded a row.
- if (!m_client->haveDecodedRow(m_frameContext->frameId(), rowBuffer, m_frameContext->width(),
+ if (!m_client->haveDecodedRow(m_frameContext->frameId(), rowBegin, m_frameContext->width(),
drowStart, drowEnd - drowStart + 1, m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass > 1))
return false;
@@ -205,20 +205,11 @@ bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock)
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.
int incode;
const unsigned char *ch;
+ size_t width = m_frameContext->width();
if (rowIter == rowBuffer.end())
return true;
-#define OUTPUT_ROW \
- do { \
- if (!outputRow()) \
- return false; \
- rowsRemaining--; \
- rowIter = rowBuffer.begin(); \
- if (!rowsRemaining) \
- return true; \
- } while (0)
-
for (ch = block; bytesInBlock-- > 0; ch++) {
// Feed the next byte into the decoder's 32-bit input buffer.
datum += ((int) *ch) << bits;
@@ -249,65 +240,95 @@ bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock)
}
if (oldcode == -1) {
+ // 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.
+ // code in the stream or the dictionary was reset. We'll write the
+ // 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.
+ firstchar = oldcode = code;
+ if (rowIter >= rowBuffer.end())
+ return false;
*rowIter++ = suffix[code];
- if (rowIter == rowBuffer.end())
- OUTPUT_ROW;
+ } else {
+ incode = code;
+ unsigned short codeLength = 0;
+ if (code < avail) {
+ // 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.
+ codeLength = suffixLength[code];
+ rowIter += codeLength;
+ 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.
+ return false;
+ } else if (code == avail) {
+ // This is an incomplete code. Code length is the length of previous
+ // code plus one. Code content is that of previous code concatenated
+ // 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.
+ codeLength = suffixLength[oldcode] + 1;
+ rowIter += codeLength;
+ if (rowIter >= rowBuffer.end())
+ return false;
+
+ // The last character of this code is the first character of the
+ // previous code. Write it to output and then write the previous 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.
+ *--rowIter = firstchar;
+ code = oldcode;
+ } else {
+ // Bad code received. Complete and incomplete codes are defined up
+ // 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.
+ return false;
+ }
- firstchar = oldcode = code;
- continue;
- }
+ while (code >= clearCode) {
+ 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
+ return false;
- incode = code;
- if (code >= avail) {
- stack[stackp++] = firstchar;
- code = oldcode;
+ // Even though suffix[] only holds characters through suffix[avail - 1],
+ // allowing code >= avail here lets us be more tolerant of malformed
+ // data. As long as code < MAX_BYTES, the only risk is a garbled image,
+ // which is no worse than refusing to display it.
+ *--rowIter = suffix[code];
+ code = prefix[code];
+ }
- if (stackp == MAX_BYTES)
- return false;
+ *--rowIter = firstchar = suffix[code];
+
+ // Define a new codeword in the dictionary.
+ 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.
+ prefix[avail] = oldcode;
+ suffix[avail] = firstchar;
+ suffixLength[avail] = suffixLength[oldcode] + 1;
+ 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.
+
+ // If we've used up all the codewords of a given length
+ // increase the length of codewords by one bit, but don't
+ // 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.
+ 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.
+ codesize++;
+ codemask += avail;
+ }
+ }
+ oldcode = incode;
+ rowIter += codeLength;
}
- while (code >= clearCode) {
- if (code >= MAX_BYTES || code == prefix[code])
- return false;
-
- // Even though suffix[] only holds characters through suffix[avail - 1],
- // allowing code >= avail here lets us be more tolerant of malformed
- // data. As long as code < MAX_BYTES, the only risk is a garbled image,
- // which is no worse than refusing to display it.
- stack[stackp++] = suffix[code];
- code = prefix[code];
+ // Not enough bytes to output row.
+ if (rowIter < rowBuffer.begin() + width)
+ 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.
- if (stackp == MAX_BYTES)
+ // There's enough data to output. Output as many rows as possible.
+ GIFRow::iterator rowBegin = rowBuffer.begin();
+ 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.
+ if (!outputRow(rowBegin))
return false;
+ rowsRemaining--;
+ if (!rowsRemaining)
+ return true;
}
- stack[stackp++] = firstchar = suffix[code];
-
- // Define a new codeword in the dictionary.
- if (avail < 4096) {
- prefix[avail] = oldcode;
- suffix[avail] = firstchar;
- avail++;
-
- // If we've used up all the codewords of a given length
- // increase the length of codewords by one bit, but don't
- // exceed the specified maximum codeword size of 12 bits.
- if ((!(avail & codemask)) && (avail < 4096)) {
- codesize++;
- codemask += avail;
- }
- }
- oldcode = incode;
-
- // Copy the decoded data out to the scanline buffer.
- do {
- *rowIter++ = stack[--stackp];
- if (rowIter == rowBuffer.end())
- OUTPUT_ROW;
- } while (stackp > 0);
+ // These bytes cannot make up a full row. Move them to the beginning
+ // 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.
+ size_t bytesToCopy = rowIter - rowBegin;
+ memcpy(rowBuffer.begin(), rowBegin, bytesToCopy);
+ rowIter = rowBuffer.begin() + bytesToCopy;
}
}
-
return true;
}
@@ -775,17 +796,18 @@ bool GIFLZWContext::prepareToDecode()
irow = 0;
// Initialize output row buffer.
- rowBuffer.resize(m_frameContext->width());
+ 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.
rowIter = rowBuffer.begin();
rowsRemaining = m_frameContext->height();
// Clearing the whole suffix table lets us be more tolerant of bad data.
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.
+ for (int i = 0; i < clearCode; ++i)
+ suffix[i] = i;
+ for (int i = 0; i < MAX_BYTES; i++)
+ suffixLength[i] = 1;
// Clearing the whole prefix table to prevent uninitialized access.
memset(prefix, 0, sizeof(prefix));
- for (int i = 0; i < clearCode; i++)
- suffix[i] = i;
- stackp = 0;
return true;
}

Powered by Google App Engine
This is Rietveld 408576698