1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Chris Saari <saari@netscape.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 The Graphics Interchange Format(c) is the copyright property of CompuServe
42 Incorporated. Only CompuServe Incorporated is authorized to define, redefine,
43 enhance, alter, modify or change in any way the definition of the format.
45 CompuServe Incorporated hereby grants a limited, non-exclusive, royalty-free
46 license for the use of the Graphics Interchange Format(sm) in computer
47 software; computer software utilizing GIF(sm) must acknowledge ownership of the
48 Graphics Interchange Format and its Service Mark by CompuServe Incorporated, in
49 User and Technical Documentation. Computer software utilizing GIF, which is
50 distributed or may be distributed without User or Technical Documentation must
51 display to the screen or printer a message acknowledging ownership of the
52 Graphics Interchange Format and the Service Mark by CompuServe Incorporated; in
53 this case, the acknowledgement may be displayed in an opening screen or leading
54 banner, or a closing screen or trailing banner. A message such as the following
57 "The Graphics Interchange Format(c) is the Copyright property of
58 CompuServe Incorporated. GIF(sm) is a Service Mark property of
59 CompuServe Incorporated."
61 For further information, please contact :
63 CompuServe Incorporated
64 Graphics Technology Department
65 5000 Arlington Center Boulevard
69 CompuServe Incorporated maintains a mailing list with all those individuals and
70 organizations who wish to receive copies of this document when it is corrected
71 or revised. This service is offered free of charge; please provide us with your
76 #include "platform/image-decoders/gif/GIFImageReader.h"
79 #include "platform/graphics/ImageSource.h"
81 using blink::GIFImageDecoder;
83 // GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'.
85 // Note, the hold will never need to be bigger than 256 bytes to gather up in the hold,
86 // as each GIF block (except colormaps) can never be bigger than 256 bytes.
87 // Colormaps are directly copied in the resp. global_colormap or dynamically allocated local_colormap.
88 // So a fixed buffer in GIFImageReader is good enough.
89 // This buffer is only needed to copy left-over data from one GifWrite call to the next
92 m_bytesToConsume = (n); \
96 // Get a 16-bit value stored in little-endian format.
97 #define GETINT16(p) ((p)[1]<<8|(p)[0])
99 // Send the data to the display front-end.
100 bool GIFLZWContext::outputRow(GIFRow::const_iterator rowBegin)
102 int drowStart = irow;
105 // Haeberli-inspired hack for interlaced GIFs: Replicate lines while
106 // displaying to diminish the "venetian-blind" effect as the image is
107 // loaded. Adjust pixel vertical positions to avoid the appearance of the
108 // image crawling up the screen as successive passes are drawn.
109 if (m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass < 4) {
111 unsigned rowShift = 0;
130 drowStart -= rowShift;
131 drowEnd = drowStart + rowDup;
133 // Extend if bottom edge isn't covered because of the shift upward.
134 if (((m_frameContext->height() - 1) - drowEnd) <= rowShift)
135 drowEnd = m_frameContext->height() - 1;
137 // Clamp first and last rows to upper and lower edge of image.
141 if ((unsigned)drowEnd >= m_frameContext->height())
142 drowEnd = m_frameContext->height() - 1;
145 // Protect against too much image data.
146 if ((unsigned)drowStart >= m_frameContext->height())
149 // CALLBACK: Let the client know we have decoded a row.
150 if (!m_client->haveDecodedRow(m_frameContext->frameId(), rowBegin, m_frameContext->width(),
151 drowStart, drowEnd - drowStart + 1, m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass > 1))
154 if (!m_frameContext->interlaced())
161 if (irow >= m_frameContext->height()) {
169 if (irow >= m_frameContext->height()) {
177 if (irow >= m_frameContext->height()) {
185 if (irow >= m_frameContext->height()) {
194 } while (irow > (m_frameContext->height() - 1));
199 // Perform Lempel-Ziv-Welch decoding.
200 // Returns true if decoding was successful. In this case the block will have been completely consumed and/or rowsRemaining will be 0.
201 // Otherwise, decoding failed; returns false in this case, which will always cause the GIFImageReader to set the "decode failed" flag.
202 bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock)
204 const size_t width = m_frameContext->width();
206 if (rowIter == rowBuffer.end())
209 for (const unsigned char* ch = block; bytesInBlock-- > 0; ch++) {
210 // Feed the next byte into the decoder's 32-bit input buffer.
211 datum += ((int) *ch) << bits;
214 // Check for underflow of decoder's 32-bit input buffer.
215 while (bits >= codesize) {
216 // Get the leading variable-length symbol from the data stream.
217 int code = datum & codemask;
221 // Reset the dictionary to its original state, if requested.
222 if (code == clearCode) {
223 codesize = m_frameContext->dataSize() + 1;
224 codemask = (1 << codesize) - 1;
225 avail = clearCode + 2;
230 // Check for explicit end-of-stream code.
231 if (code == (clearCode + 1)) {
232 // end-of-stream should only appear after all image data.
238 const int tempCode = code;
239 unsigned short codeLength = 0;
241 // This is a pre-existing code, so we already know what it
243 codeLength = suffixLength[code];
244 rowIter += codeLength;
245 } else if (code == avail && oldcode != -1) {
246 // This is a new code just being added to the dictionary.
247 // It must encode the contents of the previous code, plus
248 // the first character of the previous code again.
249 codeLength = suffixLength[oldcode] + 1;
250 rowIter += codeLength;
251 *--rowIter = firstchar;
254 // This is an invalid code. The dictionary is just initialized
255 // and the code is incomplete. We don't know how to handle
260 while (code >= clearCode) {
261 *--rowIter = suffix[code];
265 *--rowIter = firstchar = suffix[code];
267 // Define a new codeword in the dictionary as long as we've read
268 // more than one value from the stream.
269 if (avail < MAX_DICTIONARY_ENTRIES && oldcode != -1) {
270 prefix[avail] = oldcode;
271 suffix[avail] = firstchar;
272 suffixLength[avail] = suffixLength[oldcode] + 1;
275 // If we've used up all the codewords of a given length
276 // increase the length of codewords by one bit, but don't
277 // exceed the specified maximum codeword size.
278 if (!(avail & codemask) && avail < MAX_DICTIONARY_ENTRIES) {
284 rowIter += codeLength;
286 // Output as many rows as possible.
287 GIFRow::iterator rowBegin = rowBuffer.begin();
288 for (; rowBegin + width <= rowIter; rowBegin += width) {
289 if (!outputRow(rowBegin))
296 if (rowBegin != rowBuffer.begin()) {
297 // Move the remaining bytes to the beginning of the buffer.
298 const size_t bytesToCopy = rowIter - rowBegin;
299 memcpy(rowBuffer.begin(), rowBegin, bytesToCopy);
300 rowIter = rowBuffer.begin() + bytesToCopy;
307 void GIFColorMap::buildTable(const unsigned char* data, size_t length)
309 if (!m_isDefined || !m_table.isEmpty())
312 RELEASE_ASSERT(m_position + m_colors * BYTES_PER_COLORMAP_ENTRY <= length);
313 const unsigned char* srcColormap = data + m_position;
314 m_table.resize(m_colors);
315 for (Table::iterator iter = m_table.begin(); iter != m_table.end(); ++iter) {
316 *iter = SkPackARGB32NoCheck(255, srcColormap[0], srcColormap[1], srcColormap[2]);
317 srcColormap += BYTES_PER_COLORMAP_ENTRY;
321 // Perform decoding for this frame. frameDecoded will be true if the entire frame is decoded.
322 // Returns false if a decoding error occurred. This is a fatal error and causes the GIFImageReader to set the "decode failed" flag.
323 // 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.
324 bool GIFFrameContext::decode(const unsigned char* data, size_t length, blink::GIFImageDecoder* client, bool* frameDecoded)
326 m_localColorMap.buildTable(data, length);
328 *frameDecoded = false;
330 // Wait for more data to properly initialize GIFLZWContext.
331 if (!isDataSizeDefined() || !isHeaderDefined())
334 m_lzwContext = adoptPtr(new GIFLZWContext(client, this));
335 if (!m_lzwContext->prepareToDecode()) {
336 m_lzwContext.clear();
340 m_currentLzwBlock = 0;
343 // Some bad GIFs have extra blocks beyond the last row, which we don't want to decode.
344 while (m_currentLzwBlock < m_lzwBlocks.size() && m_lzwContext->hasRemainingRows()) {
345 size_t blockPosition = m_lzwBlocks[m_currentLzwBlock].blockPosition;
346 size_t blockSize = m_lzwBlocks[m_currentLzwBlock].blockSize;
347 if (blockPosition + blockSize > length)
349 if (!m_lzwContext->doLZW(data + blockPosition, blockSize))
354 // If this frame is data complete then the previous loop must have completely decoded all LZW blocks.
355 // There will be no more decoding for this frame so it's time to cleanup.
357 *frameDecoded = true;
358 m_lzwContext.clear();
364 // This method uses GIFFrameContext:decode() to decode the frame; decoding error is reported to client as a critical failure.
365 // Return true if decoding has progressed. Return false if an error has occurred.
366 bool GIFImageReader::decode(size_t frameIndex)
368 m_globalColorMap.buildTable(data(0), m_data->size());
370 bool frameDecoded = false;
371 GIFFrameContext* currentFrame = m_frames[frameIndex].get();
373 return currentFrame->decode(data(0), m_data->size(), m_client, &frameDecoded)
374 && (!frameDecoded || m_client->frameComplete(frameIndex));
377 bool GIFImageReader::parse(GIFImageDecoder::GIFParseQuery query)
379 ASSERT(m_bytesRead <= m_data->size());
381 return parseData(m_bytesRead, m_data->size() - m_bytesRead, query);
384 // Parse incoming GIF data stream into internal data structures.
385 // Return true if parsing has progressed or there is not enough data.
386 // Return false if a fatal error is encountered.
387 bool GIFImageReader::parseData(size_t dataPosition, size_t len, GIFImageDecoder::GIFParseQuery query)
390 // No new data has come in since the last call, just ignore this call.
394 if (len < m_bytesToConsume)
397 // This loop reads as many components from |m_data| as possible.
398 // At the beginning of each iteration, dataPosition will be advanced by m_bytesToConsume to
399 // point to the next component. len will be decremented accordingly.
400 while (len >= m_bytesToConsume) {
401 const size_t currentComponentPosition = dataPosition;
402 const unsigned char* currentComponent = data(dataPosition);
404 // Mark the current component as consumed. Note that currentComponent will remain pointed at this
405 // component until the next loop iteration.
406 dataPosition += m_bytesToConsume;
407 len -= m_bytesToConsume;
411 ASSERT(!m_frames.isEmpty());
412 // m_bytesToConsume is the current component size because it hasn't been updated.
413 m_frames.last()->addLzwBlock(currentComponentPosition, m_bytesToConsume);
414 GETN(1, GIFSubBlock);
418 ASSERT(!m_frames.isEmpty());
419 m_frames.last()->setDataSize(*currentComponent);
420 GETN(1, GIFSubBlock);
425 // All GIF files begin with "GIF87a" or "GIF89a".
426 if (!strncmp((char*)currentComponent, "GIF89a", 6))
428 else if (!strncmp((char*)currentComponent, "GIF87a", 6))
432 GETN(7, GIFGlobalHeader);
436 case GIFGlobalHeader: {
437 // This is the height and width of the "screen" or frame into which images are rendered. The
438 // individual images can be smaller than the screen size and located with an origin anywhere
439 // within the screen.
440 m_screenWidth = GETINT16(currentComponent);
441 m_screenHeight = GETINT16(currentComponent + 2);
443 // CALLBACK: Inform the decoderplugin of our size.
444 // Note: A subsequent frame might have dimensions larger than the "screen" dimensions.
445 if (m_client && !m_client->setSize(m_screenWidth, m_screenHeight))
448 const size_t globalColorMapColors = 2 << (currentComponent[4] & 0x07);
450 if ((currentComponent[4] & 0x80) && globalColorMapColors > 0) { /* global map */
451 m_globalColorMap.setTablePositionAndSize(dataPosition, globalColorMapColors);
452 GETN(BYTES_PER_COLORMAP_ENTRY * globalColorMapColors, GIFGlobalColormap);
456 GETN(1, GIFImageStart);
460 case GIFGlobalColormap: {
461 m_globalColorMap.setDefined();
462 GETN(1, GIFImageStart);
466 case GIFImageStart: {
467 if (*currentComponent == '!') { // extension.
468 GETN(2, GIFExtension);
472 if (*currentComponent == ',') { // image separator.
473 GETN(9, GIFImageHeader);
477 // If we get anything other than ',' (image separator), '!'
478 // (extension), or ';' (trailer), there is extraneous data
479 // between blocks. The GIF87a spec tells us to keep reading
480 // until we find an image separator, but GIF89a says such
481 // a file is corrupt. We follow Mozilla's implementation and
482 // proceed as if the file were correctly terminated, so the
489 size_t bytesInBlock = currentComponent[1];
490 GIFState exceptionState = GIFSkipBlock;
492 switch (*currentComponent) {
494 exceptionState = GIFControlExtension;
495 // The GIF spec mandates that the GIFControlExtension header block length is 4 bytes,
496 // and the parser for this block reads 4 bytes, so we must enforce that the buffer
497 // contains at least this many bytes. If the GIF specifies a different length, we
498 // allow that, so long as it's larger; the additional data will simply be ignored.
499 bytesInBlock = std::max(bytesInBlock, static_cast<size_t>(4));
502 // The GIF spec also specifies the lengths of the following two extensions' headers
503 // (as 12 and 11 bytes, respectively). Because we ignore the plain text extension entirely
504 // and sanity-check the actual length of the application extension header before reading it,
505 // we allow GIFs to deviate from these values in either direction. This is important for
506 // real-world compatibility, as GIFs in the wild exist with application extension headers
507 // that are both shorter and longer than 11 bytes.
509 // ignoring plain text extension
513 exceptionState = GIFApplicationExtension;
517 exceptionState = GIFConsumeComment;
522 GETN(bytesInBlock, exceptionState);
524 GETN(1, GIFImageStart);
528 case GIFConsumeBlock: {
529 if (!*currentComponent)
530 GETN(1, GIFImageStart);
532 GETN(*currentComponent, GIFSkipBlock);
537 GETN(1, GIFConsumeBlock);
541 case GIFControlExtension: {
542 addFrameIfNecessary();
543 GIFFrameContext* currentFrame = m_frames.last().get();
544 if (*currentComponent & 0x1)
545 currentFrame->setTransparentPixel(currentComponent[3]);
547 // We ignore the "user input" bit.
549 // NOTE: This relies on the values in the FrameDisposalMethod enum
550 // matching those in the GIF spec!
551 int disposalMethod = ((*currentComponent) >> 2) & 0x7;
552 if (disposalMethod < 4) {
553 currentFrame->setDisposalMethod(static_cast<blink::ImageFrame::DisposalMethod>(disposalMethod));
554 } else if (disposalMethod == 4) {
555 // Some specs say that disposal method 3 is "overwrite previous", others that setting
556 // the third bit of the field (i.e. method 4) is. We map both to the same value.
557 currentFrame->setDisposalMethod(blink::ImageFrame::DisposeOverwritePrevious);
559 currentFrame->setDelayTime(GETINT16(currentComponent + 1) * 10);
560 GETN(1, GIFConsumeBlock);
564 case GIFCommentExtension: {
565 if (*currentComponent)
566 GETN(*currentComponent, GIFConsumeComment);
568 GETN(1, GIFImageStart);
572 case GIFConsumeComment: {
573 GETN(1, GIFCommentExtension);
577 case GIFApplicationExtension: {
578 // Check for netscape application extension.
579 if (m_bytesToConsume == 11
580 && (!strncmp((char*)currentComponent, "NETSCAPE2.0", 11) || !strncmp((char*)currentComponent, "ANIMEXTS1.0", 11)))
581 GETN(1, GIFNetscapeExtensionBlock);
583 GETN(1, GIFConsumeBlock);
587 // Netscape-specific GIF extension: animation looping.
588 case GIFNetscapeExtensionBlock: {
589 // GIFConsumeNetscapeExtension always reads 3 bytes from the stream; we should at least wait for this amount.
590 if (*currentComponent)
591 GETN(std::max(3, static_cast<int>(*currentComponent)), GIFConsumeNetscapeExtension);
593 GETN(1, GIFImageStart);
597 // Parse netscape-specific application extensions
598 case GIFConsumeNetscapeExtension: {
599 int netscapeExtension = currentComponent[0] & 7;
601 // Loop entire animation specified # of times. Only read the loop count during the first iteration.
602 if (netscapeExtension == 1) {
603 m_loopCount = GETINT16(currentComponent + 1);
605 // Zero loop count is infinite animation loop request.
607 m_loopCount = blink::cAnimationLoopInfinite;
609 GETN(1, GIFNetscapeExtensionBlock);
610 } else if (netscapeExtension == 2) {
611 // Wait for specified # of bytes to enter buffer.
613 // Don't do this, this extension doesn't exist (isn't used at all)
614 // and doesn't do anything, as our streaming/buffering takes care of it all...
615 // See: http://semmix.pl/color/exgraf/eeg24.htm
616 GETN(1, GIFNetscapeExtensionBlock);
618 // 0,3-7 are yet to be defined netscape extension codes
624 case GIFImageHeader: {
625 unsigned height, width, xOffset, yOffset;
627 /* Get image offsets, with respect to the screen origin */
628 xOffset = GETINT16(currentComponent);
629 yOffset = GETINT16(currentComponent + 2);
631 /* Get image width and height. */
632 width = GETINT16(currentComponent + 4);
633 height = GETINT16(currentComponent + 6);
635 /* Work around broken GIF files where the logical screen
636 * size has weird width or height. We assume that GIF87a
637 * files don't contain animations.
639 if (currentFrameIsFirstFrame()
640 && ((m_screenHeight < height) || (m_screenWidth < width) || (m_version == 87))) {
641 m_screenHeight = height;
642 m_screenWidth = width;
646 // CALLBACK: Inform the decoderplugin of our size.
647 if (m_client && !m_client->setSize(m_screenWidth, m_screenHeight))
651 // Work around more broken GIF files that have zero image width or height
652 if (!height || !width) {
653 height = m_screenHeight;
654 width = m_screenWidth;
655 if (!height || !width)
659 if (query == GIFImageDecoder::GIFSizeQuery) {
660 // The decoder needs to stop. Hand back the number of bytes we consumed from
661 // buffer minus 9 (the amount we consumed to read the header).
662 setRemainingBytes(len + 9);
663 GETN(9, GIFImageHeader);
667 addFrameIfNecessary();
668 GIFFrameContext* currentFrame = m_frames.last().get();
670 currentFrame->setHeaderDefined();
671 currentFrame->setRect(xOffset, yOffset, width, height);
672 m_screenWidth = std::max(m_screenWidth, width);
673 m_screenHeight = std::max(m_screenHeight, height);
674 currentFrame->setInterlaced(currentComponent[8] & 0x40);
676 // Overlaying interlaced, transparent GIFs over
677 // existing image data using the Haeberli display hack
678 // requires saving the underlying image in order to
679 // avoid jaggies at the transparency edges. We are
680 // unprepared to deal with that, so don't display such
681 // images progressively. Which means only the first
682 // frame can be progressively displayed.
683 // FIXME: It is possible that a non-transparent frame
684 // can be interlaced and progressively displayed.
685 currentFrame->setProgressiveDisplay(currentFrameIsFirstFrame());
687 const bool isLocalColormapDefined = currentComponent[8] & 0x80;
688 if (isLocalColormapDefined) {
689 // The three low-order bits of currentComponent[8] specify the bits per pixel.
690 const size_t numColors = 2 << (currentComponent[8] & 0x7);
691 currentFrame->localColorMap().setTablePositionAndSize(dataPosition, numColors);
692 GETN(BYTES_PER_COLORMAP_ENTRY * numColors, GIFImageColormap);
696 GETN(1, GIFLZWStart);
700 case GIFImageColormap: {
701 ASSERT(!m_frames.isEmpty());
702 m_frames.last()->localColorMap().setDefined();
703 GETN(1, GIFLZWStart);
708 const size_t bytesInBlock = *currentComponent;
710 GETN(bytesInBlock, GIFLZW);
712 // Finished parsing one frame; Process next frame.
713 ASSERT(!m_frames.isEmpty());
714 // Note that some broken GIF files do not have enough LZW blocks to fully
715 // decode all rows but we treat it as frame complete.
716 m_frames.last()->setComplete();
717 GETN(1, GIFImageStart);
723 m_parseCompleted = true;
728 // We shouldn't ever get here.
734 setRemainingBytes(len);
738 void GIFImageReader::setRemainingBytes(size_t remainingBytes)
740 ASSERT(remainingBytes <= m_data->size());
741 m_bytesRead = m_data->size() - remainingBytes;
744 void GIFImageReader::addFrameIfNecessary()
746 if (m_frames.isEmpty() || m_frames.last()->isComplete())
747 m_frames.append(adoptPtr(new GIFFrameContext(m_frames.size())));
750 // FIXME: Move this method to close to doLZW().
751 bool GIFLZWContext::prepareToDecode()
753 ASSERT(m_frameContext->isDataSizeDefined() && m_frameContext->isHeaderDefined());
755 // Since we use a codesize of 1 more than the datasize, we need to ensure
756 // that our datasize is strictly less than the MAX_DICTIONARY_ENTRY_BITS.
757 if (m_frameContext->dataSize() >= MAX_DICTIONARY_ENTRY_BITS)
759 clearCode = 1 << m_frameContext->dataSize();
760 avail = clearCode + 2;
762 codesize = m_frameContext->dataSize() + 1;
763 codemask = (1 << codesize) - 1;
765 ipass = m_frameContext->interlaced() ? 1 : 0;
768 // We want to know the longest sequence encodable by a dictionary with
769 // MAX_DICTIONARY_ENTRIES entries. If we ignore the need to encode the base
770 // values themselves at the beginning of the dictionary, as well as the need
771 // for a clear code or a termination code, we could use every entry to
772 // encode a series of multiple values. If the input value stream looked
773 // like "AAAAA..." (a long string of just one value), the first dictionary
774 // entry would encode AA, the next AAA, the next AAAA, and so forth. Thus
775 // the longest sequence would be MAX_DICTIONARY_ENTRIES + 1 values.
777 // However, we have to account for reserved entries. The first |datasize|
778 // bits are reserved for the base values, and the next two entries are
779 // reserved for the clear code and termination code. In theory a GIF can
780 // set the datasize to 0, meaning we have just two reserved entries, making
781 // the longest sequence (MAX_DICTIONARY_ENTIRES + 1) - 2 values long. Since
782 // each value is a byte, this is also the number of bytes in the longest
783 // encodable sequence.
784 const size_t maxBytes = MAX_DICTIONARY_ENTRIES - 1;
786 // Now allocate the output buffer. We decode directly into this buffer
787 // until we have at least one row worth of data, then call outputRow().
788 // This means worst case we may have (row width - 1) bytes in the buffer
789 // and then decode a sequence |maxBytes| long to append.
790 rowBuffer.resize(m_frameContext->width() - 1 + maxBytes);
791 rowIter = rowBuffer.begin();
792 rowsRemaining = m_frameContext->height();
794 // Clearing the whole suffix table lets us be more tolerant of bad data.
795 for (int i = 0; i < clearCode; ++i) {