Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 | 74 |
| 75 #include "platform/image-decoders/gif/GIFImageReader.h" | 75 #include "platform/image-decoders/gif/GIFImageReader.h" |
| 76 | 76 |
| 77 #include "platform/Histogram.h" | 77 #include "platform/Histogram.h" |
| 78 #include "wtf/PtrUtil.h" | 78 #include "wtf/PtrUtil.h" |
| 79 #include "wtf/Threading.h" | 79 #include "wtf/Threading.h" |
| 80 #include <string.h> | 80 #include <string.h> |
| 81 | 81 |
| 82 using blink::GIFImageDecoder; | 82 using blink::GIFImageDecoder; |
| 83 | 83 |
| 84 // GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'. | 84 // GETN(n, s) requests at least 'n' bytes available from 'q', at start of state |
| 85 // 's'. | |
| 85 // | 86 // |
| 86 // Note, the hold will never need to be bigger than 256 bytes to gather up in th e hold, | 87 // Note: the hold will never need to be bigger than 256 bytes, as each GIF block |
| 87 // as each GIF block (except colormaps) can never be bigger than 256 bytes. | 88 // (except colormaps) can never be bigger than 256 bytes. Colormaps are directly |
| 88 // Colormaps are directly copied in the resp. global_colormap or dynamically all ocated local_colormap. | 89 // copied in the resp. global_colormap or dynamically allocated local_colormap, |
| 89 // So a fixed buffer in GIFImageReader is good enough. | 90 // so a fixed buffer in GIFImageReader is good enough. This buffer is only |
| 90 // This buffer is only needed to copy left-over data from one GifWrite call to t he next | 91 // needed to copy left-over data from one GifWrite call to the next. |
| 91 #define GETN(n, s) \ | 92 #define GETN(n, s) \ |
| 92 do { \ | 93 do { \ |
| 93 m_bytesToConsume = (n); \ | 94 m_bytesToConsume = (n); \ |
| 94 m_state = (s); \ | 95 m_state = (s); \ |
| 95 } while (0) | 96 } while (0) |
| 96 | 97 |
| 97 // Get a 16-bit value stored in little-endian format. | 98 // Get a 16-bit value stored in little-endian format. |
| 98 #define GETINT16(p) ((p)[1] << 8 | (p)[0]) | 99 #define GETINT16(p) ((p)[1] << 8 | (p)[0]) |
| 99 | 100 |
| 100 // Send the data to the display front-end. | 101 // Send the data to the display front-end. |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 break; | 194 break; |
| 194 | 195 |
| 195 default: | 196 default: |
| 196 break; | 197 break; |
| 197 } | 198 } |
| 198 } while (irow > (m_frameContext->height() - 1)); | 199 } while (irow > (m_frameContext->height() - 1)); |
| 199 } | 200 } |
| 200 return true; | 201 return true; |
| 201 } | 202 } |
| 202 | 203 |
| 203 // Perform Lempel-Ziv-Welch decoding. | 204 // Performs Lempel-Ziv-Welch decoding. Returns whether decoding was successful. |
| 204 // Returns true if decoding was successful. In this case the block will have bee n completely consumed and/or rowsRemaining will be 0. | 205 // If successful, the block will have been completely consumed and/or |
| 205 // Otherwise, decoding failed; returns false in this case, which will always cau se the GIFImageReader to set the "decode failed" flag. | 206 // rowsRemaining will be 0. |
| 206 bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock) { | 207 bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock) { |
| 207 const size_t width = m_frameContext->width(); | 208 const 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 for (const unsigned char* ch = block; bytesInBlock-- > 0; ch++) { | 213 for (const unsigned char* ch = block; bytesInBlock-- > 0; ch++) { |
| 213 // 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. |
| 214 datum += ((int)*ch) << bits; | 215 datum += ((int)*ch) << bits; |
| 215 bits += 8; | 216 bits += 8; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 reinterpret_cast<const unsigned char*>(reader->getConsecutiveData( | 320 reinterpret_cast<const unsigned char*>(reader->getConsecutiveData( |
| 320 m_position, m_colors * BYTES_PER_COLORMAP_ENTRY, buffer)); | 321 m_position, m_colors * BYTES_PER_COLORMAP_ENTRY, buffer)); |
| 321 m_table.resize(m_colors); | 322 m_table.resize(m_colors); |
| 322 for (Table::iterator iter = m_table.begin(); iter != m_table.end(); ++iter) { | 323 for (Table::iterator iter = m_table.begin(); iter != m_table.end(); ++iter) { |
| 323 *iter = SkPackARGB32NoCheck(255, srcColormap[0], srcColormap[1], | 324 *iter = SkPackARGB32NoCheck(255, srcColormap[0], srcColormap[1], |
| 324 srcColormap[2]); | 325 srcColormap[2]); |
| 325 srcColormap += BYTES_PER_COLORMAP_ENTRY; | 326 srcColormap += BYTES_PER_COLORMAP_ENTRY; |
| 326 } | 327 } |
| 327 } | 328 } |
| 328 | 329 |
| 329 // Perform decoding for this frame. frameDecoded will be true if the entire fram e is decoded. | 330 // Performs decoding for this frame. frameDecoded will be true if the entire |
|
scroggo_chromium
2016/10/04 15:36:00
nit: This sentence feels awkward to me. Why not "D
Peter Kasting
2016/10/04 16:01:58
Rewrote this comment a bit.
| |
| 330 // Returns false if a decoding error occurred. This is a fatal error and causes the GIFImageReader to set the "decode failed" flag. | 331 // frame is decoded. Returns true if decoding progressed further than before |
| 331 // 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. | 332 // without error, or there is insufficient new data to decode further. |
| 333 // Otherwise, a decoding error occurred; returns false in this case. | |
| 332 bool GIFFrameContext::decode(blink::FastSharedBufferReader* reader, | 334 bool GIFFrameContext::decode(blink::FastSharedBufferReader* reader, |
| 333 blink::GIFImageDecoder* client, | 335 blink::GIFImageDecoder* client, |
| 334 bool* frameDecoded) { | 336 bool* frameDecoded) { |
| 335 m_localColorMap.buildTable(reader); | 337 m_localColorMap.buildTable(reader); |
| 336 | 338 |
| 337 *frameDecoded = false; | 339 *frameDecoded = false; |
| 338 if (!m_lzwContext) { | 340 if (!m_lzwContext) { |
| 339 // Wait for more data to properly initialize GIFLZWContext. | 341 // Wait for more data to properly initialize GIFLZWContext. |
| 340 if (!isDataSizeDefined() || !isHeaderDefined()) | 342 if (!isDataSizeDefined() || !isHeaderDefined()) |
| 341 return true; | 343 return true; |
| 342 | 344 |
| 343 m_lzwContext = wrapUnique(new GIFLZWContext(client, this)); | 345 m_lzwContext = wrapUnique(new GIFLZWContext(client, this)); |
| 344 if (!m_lzwContext->prepareToDecode()) { | 346 if (!m_lzwContext->prepareToDecode()) { |
| 345 m_lzwContext.reset(); | 347 m_lzwContext.reset(); |
| 346 return false; | 348 return false; |
| 347 } | 349 } |
| 348 | 350 |
| 349 m_currentLzwBlock = 0; | 351 m_currentLzwBlock = 0; |
| 350 } | 352 } |
| 351 | 353 |
| 352 // Some bad GIFs have extra blocks beyond the last row, which we don't want to decode. | 354 // Some bad GIFs have extra blocks beyond the last row, which we don't want to |
| 355 // decode. | |
| 353 while (m_currentLzwBlock < m_lzwBlocks.size() && | 356 while (m_currentLzwBlock < m_lzwBlocks.size() && |
| 354 m_lzwContext->hasRemainingRows()) { | 357 m_lzwContext->hasRemainingRows()) { |
| 355 size_t blockPosition = m_lzwBlocks[m_currentLzwBlock].blockPosition; | 358 size_t blockPosition = m_lzwBlocks[m_currentLzwBlock].blockPosition; |
| 356 size_t blockSize = m_lzwBlocks[m_currentLzwBlock].blockSize; | 359 size_t blockSize = m_lzwBlocks[m_currentLzwBlock].blockSize; |
| 357 if (blockPosition + blockSize > reader->size()) | 360 if (blockPosition + blockSize > reader->size()) |
| 358 return false; | 361 return false; |
| 359 | 362 |
| 360 while (blockSize) { | 363 while (blockSize) { |
| 361 const char* segment = 0; | 364 const char* segment = 0; |
| 362 size_t segmentLength = reader->getSomeData(segment, blockPosition); | 365 size_t segmentLength = reader->getSomeData(segment, blockPosition); |
| 363 size_t decodeSize = std::min(segmentLength, blockSize); | 366 size_t decodeSize = std::min(segmentLength, blockSize); |
| 364 if (!m_lzwContext->doLZW(reinterpret_cast<const unsigned char*>(segment), | 367 if (!m_lzwContext->doLZW(reinterpret_cast<const unsigned char*>(segment), |
| 365 decodeSize)) | 368 decodeSize)) |
| 366 return false; | 369 return false; |
| 367 blockPosition += decodeSize; | 370 blockPosition += decodeSize; |
| 368 blockSize -= decodeSize; | 371 blockSize -= decodeSize; |
| 369 } | 372 } |
| 370 ++m_currentLzwBlock; | 373 ++m_currentLzwBlock; |
| 371 } | 374 } |
| 372 | 375 |
| 373 // If this frame is data complete then the previous loop must have completely decoded all LZW blocks. | 376 // If this frame is data complete then the previous loop must have completely |
| 377 // decoded all LZW blocks. | |
| 374 // There will be no more decoding for this frame so it's time to cleanup. | 378 // There will be no more decoding for this frame so it's time to cleanup. |
| 375 if (isComplete()) { | 379 if (isComplete()) { |
| 376 *frameDecoded = true; | 380 *frameDecoded = true; |
| 377 m_lzwContext.reset(); | 381 m_lzwContext.reset(); |
| 378 } | 382 } |
| 379 return true; | 383 return true; |
| 380 } | 384 } |
| 381 | 385 |
| 382 // Decode a frame. | 386 // Decodes a frame using GIFFrameContext:decode(). Returns true if decoding has |
| 383 // This method uses GIFFrameContext:decode() to decode the frame; decoding error is reported to client as a critical failure. | 387 // progressed, or false if an error has occurred. |
| 384 // Return true if decoding has progressed. Return false if an error has occurred . | |
| 385 bool GIFImageReader::decode(size_t frameIndex) { | 388 bool GIFImageReader::decode(size_t frameIndex) { |
| 386 blink::FastSharedBufferReader reader(m_data); | 389 blink::FastSharedBufferReader reader(m_data); |
| 387 m_globalColorMap.buildTable(&reader); | 390 m_globalColorMap.buildTable(&reader); |
| 388 | 391 |
| 389 bool frameDecoded = false; | 392 bool frameDecoded = false; |
| 390 GIFFrameContext* currentFrame = m_frames[frameIndex].get(); | 393 GIFFrameContext* currentFrame = m_frames[frameIndex].get(); |
| 391 | 394 |
| 392 return currentFrame->decode(&reader, m_client, &frameDecoded) && | 395 return currentFrame->decode(&reader, m_client, &frameDecoded) && |
| 393 (!frameDecoded || m_client->frameComplete(frameIndex)); | 396 (!frameDecoded || m_client->frameComplete(frameIndex)); |
| 394 } | 397 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 416 if (!len) { | 419 if (!len) { |
| 417 // No new data has come in since the last call, just ignore this call. | 420 // No new data has come in since the last call, just ignore this call. |
| 418 return true; | 421 return true; |
| 419 } | 422 } |
| 420 | 423 |
| 421 if (len < m_bytesToConsume) | 424 if (len < m_bytesToConsume) |
| 422 return true; | 425 return true; |
| 423 | 426 |
| 424 blink::FastSharedBufferReader reader(m_data); | 427 blink::FastSharedBufferReader reader(m_data); |
| 425 | 428 |
| 426 // A read buffer of 16 bytes is enough to accomodate all possible reads for pa rsing. | 429 // A read buffer of 16 bytes is enough to accomodate all possible reads for |
| 430 // parsing. | |
| 427 char readBuffer[16]; | 431 char readBuffer[16]; |
| 428 | 432 |
| 429 // This loop reads as many components from |m_data| as possible. | 433 // Read as many components from |m_data| as possible. At the beginning of each |
| 430 // At the beginning of each iteration, dataPosition will be advanced by m_byte sToConsume to | 434 // iteration, |dataPosition| is advanced by m_bytesToConsume to point to the |
| 431 // point to the next component. len will be decremented accordingly. | 435 // next component. |len| is decremented accordingly. |
| 432 while (len >= m_bytesToConsume) { | 436 while (len >= m_bytesToConsume) { |
| 433 const size_t currentComponentPosition = dataPosition; | 437 const size_t currentComponentPosition = dataPosition; |
| 434 | 438 |
| 435 // Mark the current component as consumed. Note that currentComponent will r emain pointed at this | 439 // Mark the current component as consumed. Note that currentComponent will |
| 436 // component until the next loop iteration. | 440 // remain pointed at this component until the next loop iteration. |
| 437 dataPosition += m_bytesToConsume; | 441 dataPosition += m_bytesToConsume; |
| 438 len -= m_bytesToConsume; | 442 len -= m_bytesToConsume; |
| 439 | 443 |
| 440 switch (m_state) { | 444 switch (m_state) { |
| 441 case GIFLZW: | 445 case GIFLZW: |
| 442 ASSERT(!m_frames.isEmpty()); | 446 ASSERT(!m_frames.isEmpty()); |
| 443 // m_bytesToConsume is the current component size because it hasn't been updated. | 447 // m_bytesToConsume is the current component size because it hasn't been |
| 448 // updated. | |
| 444 m_frames.last()->addLzwBlock(currentComponentPosition, | 449 m_frames.last()->addLzwBlock(currentComponentPosition, |
| 445 m_bytesToConsume); | 450 m_bytesToConsume); |
| 446 GETN(1, GIFSubBlock); | 451 GETN(1, GIFSubBlock); |
| 447 break; | 452 break; |
| 448 | 453 |
| 449 case GIFLZWStart: { | 454 case GIFLZWStart: { |
| 450 ASSERT(!m_frames.isEmpty()); | 455 ASSERT(!m_frames.isEmpty()); |
| 451 m_frames.last()->setDataSize(static_cast<unsigned char>( | 456 m_frames.last()->setDataSize(static_cast<unsigned char>( |
| 452 reader.getOneByte(currentComponentPosition))); | 457 reader.getOneByte(currentComponentPosition))); |
| 453 GETN(1, GIFSubBlock); | 458 GETN(1, GIFSubBlock); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 533 const unsigned char* currentComponent = | 538 const unsigned char* currentComponent = |
| 534 reinterpret_cast<const unsigned char*>(reader.getConsecutiveData( | 539 reinterpret_cast<const unsigned char*>(reader.getConsecutiveData( |
| 535 currentComponentPosition, 2, readBuffer)); | 540 currentComponentPosition, 2, readBuffer)); |
| 536 | 541 |
| 537 size_t bytesInBlock = currentComponent[1]; | 542 size_t bytesInBlock = currentComponent[1]; |
| 538 GIFState exceptionState = GIFSkipBlock; | 543 GIFState exceptionState = GIFSkipBlock; |
| 539 | 544 |
| 540 switch (*currentComponent) { | 545 switch (*currentComponent) { |
| 541 case 0xf9: | 546 case 0xf9: |
| 542 exceptionState = GIFControlExtension; | 547 exceptionState = GIFControlExtension; |
| 543 // The GIF spec mandates that the GIFControlExtension header block l ength is 4 bytes, | 548 // The GIF spec mandates that the GIFControlExtension header block |
| 544 // and the parser for this block reads 4 bytes, so we must enforce t hat the buffer | 549 // length is 4 bytes, and the parser for this block reads 4 bytes, |
| 545 // contains at least this many bytes. If the GIF specifies a differe nt length, we | 550 // so we must enforce that the buffer contains at least this many |
| 546 // allow that, so long as it's larger; the additional data will simp ly be ignored. | 551 // bytes. If the GIF specifies a different length, we allow that, so |
| 552 // long as it's larger; the additional data will simply be ignored. | |
| 547 bytesInBlock = std::max(bytesInBlock, static_cast<size_t>(4)); | 553 bytesInBlock = std::max(bytesInBlock, static_cast<size_t>(4)); |
| 548 break; | 554 break; |
| 549 | 555 |
| 550 // The GIF spec also specifies the lengths of the following two extens ions' headers | 556 // The GIF spec also specifies the lengths of the following two |
| 551 // (as 12 and 11 bytes, respectively). Because we ignore the plain tex t extension entirely | 557 // extensions' headers (as 12 and 11 bytes, respectively). Because we |
| 552 // and sanity-check the actual length of the application extension hea der before reading it, | 558 // ignore the plain text extension entirely and sanity-check the |
| 553 // we allow GIFs to deviate from these values in either direction. Thi s is important for | 559 // actual length of the application extension header before reading |
| 554 // real-world compatibility, as GIFs in the wild exist with applicatio n extension headers | 560 // it, we allow GIFs to deviate from these values in either direction. |
| 555 // that are both shorter and longer than 11 bytes. | 561 // This is important for real-world compatibility, as GIFs in the wild |
| 562 // exist with application extension headers that are both shorter and | |
| 563 // longer than 11 bytes. | |
| 556 case 0x01: | 564 case 0x01: |
| 557 // ignoring plain text extension | 565 // ignoring plain text extension |
| 558 break; | 566 break; |
| 559 | 567 |
| 560 case 0xff: | 568 case 0xff: |
| 561 exceptionState = GIFApplicationExtension; | 569 exceptionState = GIFApplicationExtension; |
| 562 break; | 570 break; |
| 563 | 571 |
| 564 case 0xfe: | 572 case 0xfe: |
| 565 exceptionState = GIFConsumeComment; | 573 exceptionState = GIFConsumeComment; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 | 608 |
| 601 // We ignore the "user input" bit. | 609 // We ignore the "user input" bit. |
| 602 | 610 |
| 603 // NOTE: This relies on the values in the FrameDisposalMethod enum | 611 // NOTE: This relies on the values in the FrameDisposalMethod enum |
| 604 // matching those in the GIF spec! | 612 // matching those in the GIF spec! |
| 605 int disposalMethod = ((*currentComponent) >> 2) & 0x7; | 613 int disposalMethod = ((*currentComponent) >> 2) & 0x7; |
| 606 if (disposalMethod < 4) { | 614 if (disposalMethod < 4) { |
| 607 currentFrame->setDisposalMethod( | 615 currentFrame->setDisposalMethod( |
| 608 static_cast<blink::ImageFrame::DisposalMethod>(disposalMethod)); | 616 static_cast<blink::ImageFrame::DisposalMethod>(disposalMethod)); |
| 609 } else if (disposalMethod == 4) { | 617 } else if (disposalMethod == 4) { |
| 610 // Some specs say that disposal method 3 is "overwrite previous", othe rs that setting | 618 // Some specs say that disposal method 3 is "overwrite previous", |
| 611 // the third bit of the field (i.e. method 4) is. We map both to the s ame value. | 619 // others that setting the third bit of the field (i.e. method 4) is. |
| 620 // We map both to the same value. | |
| 612 currentFrame->setDisposalMethod( | 621 currentFrame->setDisposalMethod( |
| 613 blink::ImageFrame::DisposeOverwritePrevious); | 622 blink::ImageFrame::DisposeOverwritePrevious); |
| 614 } | 623 } |
| 615 currentFrame->setDelayTime(GETINT16(currentComponent + 1) * 10); | 624 currentFrame->setDelayTime(GETINT16(currentComponent + 1) * 10); |
| 616 GETN(1, GIFConsumeBlock); | 625 GETN(1, GIFConsumeBlock); |
| 617 break; | 626 break; |
| 618 } | 627 } |
| 619 | 628 |
| 620 case GIFCommentExtension: { | 629 case GIFCommentExtension: { |
| 621 const unsigned char currentComponent = static_cast<unsigned char>( | 630 const unsigned char currentComponent = static_cast<unsigned char>( |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 646 | 655 |
| 647 if (m_state != GIFNetscapeExtensionBlock) | 656 if (m_state != GIFNetscapeExtensionBlock) |
| 648 GETN(1, GIFConsumeBlock); | 657 GETN(1, GIFConsumeBlock); |
| 649 break; | 658 break; |
| 650 } | 659 } |
| 651 | 660 |
| 652 // Netscape-specific GIF extension: animation looping. | 661 // Netscape-specific GIF extension: animation looping. |
| 653 case GIFNetscapeExtensionBlock: { | 662 case GIFNetscapeExtensionBlock: { |
| 654 const int currentComponent = static_cast<unsigned char>( | 663 const int currentComponent = static_cast<unsigned char>( |
| 655 reader.getOneByte(currentComponentPosition)); | 664 reader.getOneByte(currentComponentPosition)); |
| 656 // GIFConsumeNetscapeExtension always reads 3 bytes from the stream; we should at least wait for this amount. | 665 // GIFConsumeNetscapeExtension always reads 3 bytes from the stream; we |
| 666 // should at least wait for this amount. | |
| 657 if (currentComponent) | 667 if (currentComponent) |
| 658 GETN(std::max(3, currentComponent), GIFConsumeNetscapeExtension); | 668 GETN(std::max(3, currentComponent), GIFConsumeNetscapeExtension); |
| 659 else | 669 else |
| 660 GETN(1, GIFImageStart); | 670 GETN(1, GIFImageStart); |
| 661 break; | 671 break; |
| 662 } | 672 } |
| 663 | 673 |
| 664 // Parse netscape-specific application extensions | 674 // Parse netscape-specific application extensions |
| 665 case GIFConsumeNetscapeExtension: { | 675 case GIFConsumeNetscapeExtension: { |
| 666 const unsigned char* currentComponent = | 676 const unsigned char* currentComponent = |
| 667 reinterpret_cast<const unsigned char*>(reader.getConsecutiveData( | 677 reinterpret_cast<const unsigned char*>(reader.getConsecutiveData( |
| 668 currentComponentPosition, 3, readBuffer)); | 678 currentComponentPosition, 3, readBuffer)); |
| 669 | 679 |
| 670 int netscapeExtension = currentComponent[0] & 7; | 680 int netscapeExtension = currentComponent[0] & 7; |
| 671 | 681 |
| 672 // Loop entire animation specified # of times. Only read the loop count during the first iteration. | 682 // Loop entire animation specified # of times. Only read the loop count |
| 683 // during the first iteration. | |
| 673 if (netscapeExtension == 1) { | 684 if (netscapeExtension == 1) { |
| 674 m_loopCount = GETINT16(currentComponent + 1); | 685 m_loopCount = GETINT16(currentComponent + 1); |
| 675 | 686 |
| 676 // Zero loop count is infinite animation loop request. | 687 // Zero loop count is infinite animation loop request. |
| 677 if (!m_loopCount) | 688 if (!m_loopCount) |
| 678 m_loopCount = blink::cAnimationLoopInfinite; | 689 m_loopCount = blink::cAnimationLoopInfinite; |
| 679 | 690 |
| 680 GETN(1, GIFNetscapeExtensionBlock); | 691 GETN(1, GIFNetscapeExtensionBlock); |
| 681 } else if (netscapeExtension == 2) { | 692 } else if (netscapeExtension == 2) { |
| 682 // Wait for specified # of bytes to enter buffer. | 693 // Wait for specified # of bytes to enter buffer. |
| 683 | 694 |
| 684 // Don't do this, this extension doesn't exist (isn't used at all) | 695 // Don't do this, this extension doesn't exist (isn't used at all) |
| 685 // and doesn't do anything, as our streaming/buffering takes care of i t all... | 696 // and doesn't do anything, as our streaming/buffering takes care of |
| 686 // See: http://semmix.pl/color/exgraf/eeg24.htm | 697 // it all. See http://semmix.pl/color/exgraf/eeg24.htm . |
| 687 GETN(1, GIFNetscapeExtensionBlock); | 698 GETN(1, GIFNetscapeExtensionBlock); |
| 688 } else { | 699 } else { |
| 689 // 0,3-7 are yet to be defined netscape extension codes | 700 // 0,3-7 are yet to be defined netscape extension codes |
| 690 return false; | 701 return false; |
| 691 } | 702 } |
| 692 break; | 703 break; |
| 693 } | 704 } |
| 694 | 705 |
| 695 case GIFImageHeader: { | 706 case GIFImageHeader: { |
| 696 unsigned height, width, xOffset, yOffset; | 707 unsigned height, width, xOffset, yOffset; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 755 m_screenWidth = std::max(m_screenWidth, xOffset + width); | 766 m_screenWidth = std::max(m_screenWidth, xOffset + width); |
| 756 } | 767 } |
| 757 | 768 |
| 758 // Inform the client of the final size. | 769 // Inform the client of the final size. |
| 759 if (!m_sentSizeToClient && m_client && | 770 if (!m_sentSizeToClient && m_client && |
| 760 !m_client->setSize(m_screenWidth, m_screenHeight)) | 771 !m_client->setSize(m_screenWidth, m_screenHeight)) |
| 761 return false; | 772 return false; |
| 762 m_sentSizeToClient = true; | 773 m_sentSizeToClient = true; |
| 763 | 774 |
| 764 if (query == GIFImageDecoder::GIFSizeQuery) { | 775 if (query == GIFImageDecoder::GIFSizeQuery) { |
| 765 // The decoder needs to stop. Hand back the number of bytes we consume d from | 776 // The decoder needs to stop. Hand back the number of bytes we |
| 766 // buffer minus 9 (the amount we consumed to read the header). | 777 // consumed from the buffer minus 9 (the amount we consumed to read |
| 778 // the header). | |
| 767 setRemainingBytes(len + 9); | 779 setRemainingBytes(len + 9); |
| 768 GETN(9, GIFImageHeader); | 780 GETN(9, GIFImageHeader); |
| 769 return true; | 781 return true; |
| 770 } | 782 } |
| 771 | 783 |
| 772 addFrameIfNecessary(); | 784 addFrameIfNecessary(); |
| 773 GIFFrameContext* currentFrame = m_frames.last().get(); | 785 GIFFrameContext* currentFrame = m_frames.last().get(); |
| 774 | 786 |
| 775 currentFrame->setHeaderDefined(); | 787 currentFrame->setHeaderDefined(); |
| 776 | 788 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 791 // avoid jaggies at the transparency edges. We are | 803 // avoid jaggies at the transparency edges. We are |
| 792 // unprepared to deal with that, so don't display such | 804 // unprepared to deal with that, so don't display such |
| 793 // images progressively. Which means only the first | 805 // images progressively. Which means only the first |
| 794 // frame can be progressively displayed. | 806 // frame can be progressively displayed. |
| 795 // FIXME: It is possible that a non-transparent frame | 807 // FIXME: It is possible that a non-transparent frame |
| 796 // can be interlaced and progressively displayed. | 808 // can be interlaced and progressively displayed. |
| 797 currentFrame->setProgressiveDisplay(currentFrameIsFirstFrame()); | 809 currentFrame->setProgressiveDisplay(currentFrameIsFirstFrame()); |
| 798 | 810 |
| 799 const bool isLocalColormapDefined = currentComponent[8] & 0x80; | 811 const bool isLocalColormapDefined = currentComponent[8] & 0x80; |
| 800 if (isLocalColormapDefined) { | 812 if (isLocalColormapDefined) { |
| 801 // The three low-order bits of currentComponent[8] specify the bits pe r pixel. | 813 // The three low-order bits of currentComponent[8] specify the bits |
| 814 // per pixel. | |
| 802 const size_t numColors = 2 << (currentComponent[8] & 0x7); | 815 const size_t numColors = 2 << (currentComponent[8] & 0x7); |
| 803 currentFrame->localColorMap().setTablePositionAndSize(dataPosition, | 816 currentFrame->localColorMap().setTablePositionAndSize(dataPosition, |
| 804 numColors); | 817 numColors); |
| 805 GETN(BYTES_PER_COLORMAP_ENTRY * numColors, GIFImageColormap); | 818 GETN(BYTES_PER_COLORMAP_ENTRY * numColors, GIFImageColormap); |
| 806 break; | 819 break; |
| 807 } | 820 } |
| 808 | 821 |
| 809 GETN(1, GIFLZWStart); | 822 GETN(1, GIFLZWStart); |
| 810 break; | 823 break; |
| 811 } | 824 } |
| 812 | 825 |
| 813 case GIFImageColormap: { | 826 case GIFImageColormap: { |
| 814 ASSERT(!m_frames.isEmpty()); | 827 ASSERT(!m_frames.isEmpty()); |
| 815 m_frames.last()->localColorMap().setDefined(); | 828 m_frames.last()->localColorMap().setDefined(); |
| 816 GETN(1, GIFLZWStart); | 829 GETN(1, GIFLZWStart); |
| 817 break; | 830 break; |
| 818 } | 831 } |
| 819 | 832 |
| 820 case GIFSubBlock: { | 833 case GIFSubBlock: { |
| 821 const size_t bytesInBlock = static_cast<unsigned char>( | 834 const size_t bytesInBlock = static_cast<unsigned char>( |
| 822 reader.getOneByte(currentComponentPosition)); | 835 reader.getOneByte(currentComponentPosition)); |
| 823 if (bytesInBlock) | 836 if (bytesInBlock) |
| 824 GETN(bytesInBlock, GIFLZW); | 837 GETN(bytesInBlock, GIFLZW); |
| 825 else { | 838 else { |
| 826 // Finished parsing one frame; Process next frame. | 839 // Finished parsing one frame; Process next frame. |
| 827 ASSERT(!m_frames.isEmpty()); | 840 ASSERT(!m_frames.isEmpty()); |
| 828 // Note that some broken GIF files do not have enough LZW blocks to fu lly | 841 // Note that some broken GIF files do not have enough LZW blocks to |
| 829 // decode all rows but we treat it as frame complete. | 842 // fully decode all rows; we treat this case as "frame complete". |
| 830 m_frames.last()->setComplete(); | 843 m_frames.last()->setComplete(); |
| 831 GETN(1, GIFImageStart); | 844 GETN(1, GIFImageStart); |
| 832 } | 845 } |
| 833 break; | 846 break; |
| 834 } | 847 } |
| 835 | 848 |
| 836 case GIFDone: { | 849 case GIFDone: { |
| 837 m_parseCompleted = true; | 850 m_parseCompleted = true; |
| 838 return true; | 851 return true; |
| 839 } | 852 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 903 rowIter = rowBuffer.begin(); | 916 rowIter = rowBuffer.begin(); |
| 904 rowsRemaining = m_frameContext->height(); | 917 rowsRemaining = m_frameContext->height(); |
| 905 | 918 |
| 906 // Clearing the whole suffix table lets us be more tolerant of bad data. | 919 // Clearing the whole suffix table lets us be more tolerant of bad data. |
| 907 for (int i = 0; i < clearCode; ++i) { | 920 for (int i = 0; i < clearCode; ++i) { |
| 908 suffix[i] = i; | 921 suffix[i] = i; |
| 909 suffixLength[i] = 1; | 922 suffixLength[i] = 1; |
| 910 } | 923 } |
| 911 return true; | 924 return true; |
| 912 } | 925 } |
| OLD | NEW |