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 // Decodes this frame. |frameDecoded| will be set to true if the entire frame is |
330 // Returns false if a decoding error occurred. This is a fatal error and causes
the GIFImageReader to set the "decode failed" flag. | 331 // decoded. Returns true if decoding progressed further than before without |
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 // error, or there is insufficient new data to decode further. Otherwise, a |
| 333 // 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 |