| Index: third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp
|
| diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp
|
| index bae396e5e1e77cc5ad03621c9fe7b442e6434596..d94b2e6f4b7071cc3096400ff71990fa70054f9a 100644
|
| --- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp
|
| +++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.cpp
|
| @@ -81,13 +81,14 @@ mailing address.
|
|
|
| using blink::GIFImageDecoder;
|
|
|
| -// GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'.
|
| +// GETN(n, s) requests at least 'n' bytes available from 'q', at start of state
|
| +// 's'.
|
| //
|
| -// Note, the hold will never need to be bigger than 256 bytes to gather up in the hold,
|
| -// as each GIF block (except colormaps) can never be bigger than 256 bytes.
|
| -// Colormaps are directly copied in the resp. global_colormap or dynamically allocated local_colormap.
|
| -// So a fixed buffer in GIFImageReader is good enough.
|
| -// This buffer is only needed to copy left-over data from one GifWrite call to the next
|
| +// Note: the hold will never need to be bigger than 256 bytes, as each GIF block
|
| +// (except colormaps) can never be bigger than 256 bytes. Colormaps are directly
|
| +// copied in the resp. global_colormap or dynamically allocated local_colormap,
|
| +// so a fixed buffer in GIFImageReader is good enough. This buffer is only
|
| +// needed to copy left-over data from one GifWrite call to the next.
|
| #define GETN(n, s) \
|
| do { \
|
| m_bytesToConsume = (n); \
|
| @@ -200,9 +201,9 @@ bool GIFLZWContext::outputRow(GIFRow::const_iterator rowBegin) {
|
| return true;
|
| }
|
|
|
| -// Perform Lempel-Ziv-Welch decoding.
|
| -// Returns true if decoding was successful. In this case the block will have been completely consumed and/or rowsRemaining will be 0.
|
| -// Otherwise, decoding failed; returns false in this case, which will always cause the GIFImageReader to set the "decode failed" flag.
|
| +// Performs Lempel-Ziv-Welch decoding. Returns whether decoding was successful.
|
| +// If successful, the block will have been completely consumed and/or
|
| +// rowsRemaining will be 0.
|
| bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock) {
|
| const size_t width = m_frameContext->width();
|
|
|
| @@ -326,9 +327,10 @@ void GIFColorMap::buildTable(blink::FastSharedBufferReader* reader) {
|
| }
|
| }
|
|
|
| -// Perform decoding for this frame. frameDecoded will be true if the entire frame is decoded.
|
| -// Returns false if a decoding error occurred. This is a fatal error and causes the GIFImageReader to set the "decode failed" flag.
|
| -// Otherwise, either not enough data is available to decode further than before, or the new data has been decoded successfully; returns true in this case.
|
| +// Decodes this frame. |frameDecoded| will be set to true if the entire frame is
|
| +// decoded. Returns true if decoding progressed further than before without
|
| +// error, or there is insufficient new data to decode further. Otherwise, a
|
| +// decoding error occurred; returns false in this case.
|
| bool GIFFrameContext::decode(blink::FastSharedBufferReader* reader,
|
| blink::GIFImageDecoder* client,
|
| bool* frameDecoded) {
|
| @@ -349,7 +351,8 @@ bool GIFFrameContext::decode(blink::FastSharedBufferReader* reader,
|
| m_currentLzwBlock = 0;
|
| }
|
|
|
| - // Some bad GIFs have extra blocks beyond the last row, which we don't want to decode.
|
| + // Some bad GIFs have extra blocks beyond the last row, which we don't want to
|
| + // decode.
|
| while (m_currentLzwBlock < m_lzwBlocks.size() &&
|
| m_lzwContext->hasRemainingRows()) {
|
| size_t blockPosition = m_lzwBlocks[m_currentLzwBlock].blockPosition;
|
| @@ -370,7 +373,8 @@ bool GIFFrameContext::decode(blink::FastSharedBufferReader* reader,
|
| ++m_currentLzwBlock;
|
| }
|
|
|
| - // If this frame is data complete then the previous loop must have completely decoded all LZW blocks.
|
| + // If this frame is data complete then the previous loop must have completely
|
| + // decoded all LZW blocks.
|
| // There will be no more decoding for this frame so it's time to cleanup.
|
| if (isComplete()) {
|
| *frameDecoded = true;
|
| @@ -379,9 +383,8 @@ bool GIFFrameContext::decode(blink::FastSharedBufferReader* reader,
|
| return true;
|
| }
|
|
|
| -// Decode a frame.
|
| -// This method uses GIFFrameContext:decode() to decode the frame; decoding error is reported to client as a critical failure.
|
| -// Return true if decoding has progressed. Return false if an error has occurred.
|
| +// Decodes a frame using GIFFrameContext:decode(). Returns true if decoding has
|
| +// progressed, or false if an error has occurred.
|
| bool GIFImageReader::decode(size_t frameIndex) {
|
| blink::FastSharedBufferReader reader(m_data);
|
| m_globalColorMap.buildTable(&reader);
|
| @@ -423,24 +426,26 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
|
|
| blink::FastSharedBufferReader reader(m_data);
|
|
|
| - // A read buffer of 16 bytes is enough to accomodate all possible reads for parsing.
|
| + // A read buffer of 16 bytes is enough to accomodate all possible reads for
|
| + // parsing.
|
| char readBuffer[16];
|
|
|
| - // This loop reads as many components from |m_data| as possible.
|
| - // At the beginning of each iteration, dataPosition will be advanced by m_bytesToConsume to
|
| - // point to the next component. len will be decremented accordingly.
|
| + // Read as many components from |m_data| as possible. At the beginning of each
|
| + // iteration, |dataPosition| is advanced by m_bytesToConsume to point to the
|
| + // next component. |len| is decremented accordingly.
|
| while (len >= m_bytesToConsume) {
|
| const size_t currentComponentPosition = dataPosition;
|
|
|
| - // Mark the current component as consumed. Note that currentComponent will remain pointed at this
|
| - // component until the next loop iteration.
|
| + // Mark the current component as consumed. Note that currentComponent will
|
| + // remain pointed at this component until the next loop iteration.
|
| dataPosition += m_bytesToConsume;
|
| len -= m_bytesToConsume;
|
|
|
| switch (m_state) {
|
| case GIFLZW:
|
| ASSERT(!m_frames.isEmpty());
|
| - // m_bytesToConsume is the current component size because it hasn't been updated.
|
| + // m_bytesToConsume is the current component size because it hasn't been
|
| + // updated.
|
| m_frames.last()->addLzwBlock(currentComponentPosition,
|
| m_bytesToConsume);
|
| GETN(1, GIFSubBlock);
|
| @@ -540,19 +545,22 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
| switch (*currentComponent) {
|
| case 0xf9:
|
| exceptionState = GIFControlExtension;
|
| - // The GIF spec mandates that the GIFControlExtension header block length is 4 bytes,
|
| - // and the parser for this block reads 4 bytes, so we must enforce that the buffer
|
| - // contains at least this many bytes. If the GIF specifies a different length, we
|
| - // allow that, so long as it's larger; the additional data will simply be ignored.
|
| + // The GIF spec mandates that the GIFControlExtension header block
|
| + // length is 4 bytes, and the parser for this block reads 4 bytes,
|
| + // so we must enforce that the buffer contains at least this many
|
| + // bytes. If the GIF specifies a different length, we allow that, so
|
| + // long as it's larger; the additional data will simply be ignored.
|
| bytesInBlock = std::max(bytesInBlock, static_cast<size_t>(4));
|
| break;
|
|
|
| - // The GIF spec also specifies the lengths of the following two extensions' headers
|
| - // (as 12 and 11 bytes, respectively). Because we ignore the plain text extension entirely
|
| - // and sanity-check the actual length of the application extension header before reading it,
|
| - // we allow GIFs to deviate from these values in either direction. This is important for
|
| - // real-world compatibility, as GIFs in the wild exist with application extension headers
|
| - // that are both shorter and longer than 11 bytes.
|
| + // The GIF spec also specifies the lengths of the following two
|
| + // extensions' headers (as 12 and 11 bytes, respectively). Because we
|
| + // ignore the plain text extension entirely and sanity-check the
|
| + // actual length of the application extension header before reading
|
| + // it, we allow GIFs to deviate from these values in either direction.
|
| + // This is important for real-world compatibility, as GIFs in the wild
|
| + // exist with application extension headers that are both shorter and
|
| + // longer than 11 bytes.
|
| case 0x01:
|
| // ignoring plain text extension
|
| break;
|
| @@ -607,8 +615,9 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
| currentFrame->setDisposalMethod(
|
| static_cast<blink::ImageFrame::DisposalMethod>(disposalMethod));
|
| } else if (disposalMethod == 4) {
|
| - // Some specs say that disposal method 3 is "overwrite previous", others that setting
|
| - // the third bit of the field (i.e. method 4) is. We map both to the same value.
|
| + // Some specs say that disposal method 3 is "overwrite previous",
|
| + // others that setting the third bit of the field (i.e. method 4) is.
|
| + // We map both to the same value.
|
| currentFrame->setDisposalMethod(
|
| blink::ImageFrame::DisposeOverwritePrevious);
|
| }
|
| @@ -653,7 +662,8 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
| case GIFNetscapeExtensionBlock: {
|
| const int currentComponent = static_cast<unsigned char>(
|
| reader.getOneByte(currentComponentPosition));
|
| - // GIFConsumeNetscapeExtension always reads 3 bytes from the stream; we should at least wait for this amount.
|
| + // GIFConsumeNetscapeExtension always reads 3 bytes from the stream; we
|
| + // should at least wait for this amount.
|
| if (currentComponent)
|
| GETN(std::max(3, currentComponent), GIFConsumeNetscapeExtension);
|
| else
|
| @@ -669,7 +679,8 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
|
|
| int netscapeExtension = currentComponent[0] & 7;
|
|
|
| - // Loop entire animation specified # of times. Only read the loop count during the first iteration.
|
| + // Loop entire animation specified # of times. Only read the loop count
|
| + // during the first iteration.
|
| if (netscapeExtension == 1) {
|
| m_loopCount = GETINT16(currentComponent + 1);
|
|
|
| @@ -682,8 +693,8 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
| // Wait for specified # of bytes to enter buffer.
|
|
|
| // Don't do this, this extension doesn't exist (isn't used at all)
|
| - // and doesn't do anything, as our streaming/buffering takes care of it all...
|
| - // See: http://semmix.pl/color/exgraf/eeg24.htm
|
| + // and doesn't do anything, as our streaming/buffering takes care of
|
| + // it all. See http://semmix.pl/color/exgraf/eeg24.htm .
|
| GETN(1, GIFNetscapeExtensionBlock);
|
| } else {
|
| // 0,3-7 are yet to be defined netscape extension codes
|
| @@ -762,8 +773,9 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
| m_sentSizeToClient = true;
|
|
|
| if (query == GIFImageDecoder::GIFSizeQuery) {
|
| - // The decoder needs to stop. Hand back the number of bytes we consumed from
|
| - // buffer minus 9 (the amount we consumed to read the header).
|
| + // The decoder needs to stop. Hand back the number of bytes we
|
| + // consumed from the buffer minus 9 (the amount we consumed to read
|
| + // the header).
|
| setRemainingBytes(len + 9);
|
| GETN(9, GIFImageHeader);
|
| return true;
|
| @@ -798,7 +810,8 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
|
|
| const bool isLocalColormapDefined = currentComponent[8] & 0x80;
|
| if (isLocalColormapDefined) {
|
| - // The three low-order bits of currentComponent[8] specify the bits per pixel.
|
| + // The three low-order bits of currentComponent[8] specify the bits
|
| + // per pixel.
|
| const size_t numColors = 2 << (currentComponent[8] & 0x7);
|
| currentFrame->localColorMap().setTablePositionAndSize(dataPosition,
|
| numColors);
|
| @@ -825,8 +838,8 @@ bool GIFImageReader::parseData(size_t dataPosition,
|
| else {
|
| // Finished parsing one frame; Process next frame.
|
| ASSERT(!m_frames.isEmpty());
|
| - // Note that some broken GIF files do not have enough LZW blocks to fully
|
| - // decode all rows but we treat it as frame complete.
|
| + // Note that some broken GIF files do not have enough LZW blocks to
|
| + // fully decode all rows; we treat this case as "frame complete".
|
| m_frames.last()->setComplete();
|
| GETN(1, GIFImageStart);
|
| }
|
|
|