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 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 m_version = 89; | 427 m_version = 89; |
428 else if (!strncmp((char*)currentComponent, "GIF87a", 6)) | 428 else if (!strncmp((char*)currentComponent, "GIF87a", 6)) |
429 m_version = 87; | 429 m_version = 87; |
430 else | 430 else |
431 return false; | 431 return false; |
432 GETN(7, GIFGlobalHeader); | 432 GETN(7, GIFGlobalHeader); |
433 break; | 433 break; |
434 } | 434 } |
435 | 435 |
436 case GIFGlobalHeader: { | 436 case GIFGlobalHeader: { |
437 // This is the height and width of the "screen" or frame into which
images are rendered. The | 437 // This is the height and width of the "screen" or frame into which |
438 // individual images can be smaller than the screen size and located
with an origin anywhere | 438 // images are rendered. The individual images can be smaller than |
439 // within the screen. | 439 // the screen size and located with an origin anywhere within the |
| 440 // screen. |
| 441 // Note that we don't inform the client of the size yet, as it might |
| 442 // change after we read the first frame's image header. |
440 m_screenWidth = GETINT16(currentComponent); | 443 m_screenWidth = GETINT16(currentComponent); |
441 m_screenHeight = GETINT16(currentComponent + 2); | 444 m_screenHeight = GETINT16(currentComponent + 2); |
442 | 445 |
443 // CALLBACK: Inform the decoderplugin of our size. | |
444 // Note: A subsequent frame might have dimensions larger than the "s
creen" dimensions. | |
445 if (m_client && !m_client->setSize(m_screenWidth, m_screenHeight)) | |
446 return false; | |
447 | |
448 const size_t globalColorMapColors = 2 << (currentComponent[4] & 0x07
); | 446 const size_t globalColorMapColors = 2 << (currentComponent[4] & 0x07
); |
449 | 447 |
450 if ((currentComponent[4] & 0x80) && globalColorMapColors > 0) { /* g
lobal map */ | 448 if ((currentComponent[4] & 0x80) && globalColorMapColors > 0) { /* g
lobal map */ |
451 m_globalColorMap.setTablePositionAndSize(dataPosition, globalCol
orMapColors); | 449 m_globalColorMap.setTablePositionAndSize(dataPosition, globalCol
orMapColors); |
452 GETN(BYTES_PER_COLORMAP_ENTRY * globalColorMapColors, GIFGlobalC
olormap); | 450 GETN(BYTES_PER_COLORMAP_ENTRY * globalColorMapColors, GIFGlobalC
olormap); |
453 break; | 451 break; |
454 } | 452 } |
455 | 453 |
456 GETN(1, GIFImageStart); | 454 GETN(1, GIFImageStart); |
457 break; | 455 break; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 unsigned height, width, xOffset, yOffset; | 623 unsigned height, width, xOffset, yOffset; |
626 | 624 |
627 /* Get image offsets, with respect to the screen origin */ | 625 /* Get image offsets, with respect to the screen origin */ |
628 xOffset = GETINT16(currentComponent); | 626 xOffset = GETINT16(currentComponent); |
629 yOffset = GETINT16(currentComponent + 2); | 627 yOffset = GETINT16(currentComponent + 2); |
630 | 628 |
631 /* Get image width and height. */ | 629 /* Get image width and height. */ |
632 width = GETINT16(currentComponent + 4); | 630 width = GETINT16(currentComponent + 4); |
633 height = GETINT16(currentComponent + 6); | 631 height = GETINT16(currentComponent + 6); |
634 | 632 |
635 /* Work around broken GIF files where the logical screen | 633 // Some GIF files have frames that don't fit in the specified |
636 * size has weird width or height. We assume that GIF87a | 634 // overall image size. For the first frame, we can simply enlarge |
637 * files don't contain animations. | 635 // the image size to allow the frame to be visible. We can't do |
638 */ | 636 // this on subsequent frames because the rest of the decoding |
639 if (currentFrameIsFirstFrame() | 637 // infrastructure assumes the image size won't change as we |
640 && ((m_screenHeight < height) || (m_screenWidth < width) || (m_v
ersion == 87))) { | 638 // continue decoding, so any subsequent frames that are even |
641 m_screenHeight = height; | 639 // larger will be cropped. |
642 m_screenWidth = width; | 640 // Luckily, handling just the first frame is sufficient to deal |
643 xOffset = 0; | 641 // with most cases, e.g. ones where the image size is erroneously |
644 yOffset = 0; | 642 // set to zero, since usually the first frame completely fills |
645 | 643 // the image. |
646 // CALLBACK: Inform the decoderplugin of our size. | 644 if (currentFrameIsFirstFrame()) { |
647 if (m_client && !m_client->setSize(m_screenWidth, m_screenHeight
)) | 645 m_screenHeight = std::max(m_screenHeight, yOffset + height); |
648 return false; | 646 m_screenWidth = std::max(m_screenWidth, xOffset + width); |
649 } | 647 } |
650 | 648 |
651 // Work around more broken GIF files that have zero image width or h
eight | 649 // Inform the client of the final size. |
652 if (!height || !width) { | 650 if (!m_sentSizeToClient && m_client && !m_client->setSize(m_screenWi
dth, m_screenHeight)) |
653 height = m_screenHeight; | 651 return false; |
654 width = m_screenWidth; | 652 m_sentSizeToClient = true; |
655 if (!height || !width) | |
656 return false; | |
657 } | |
658 | 653 |
659 if (query == GIFImageDecoder::GIFSizeQuery) { | 654 if (query == GIFImageDecoder::GIFSizeQuery) { |
660 // The decoder needs to stop. Hand back the number of bytes we c
onsumed from | 655 // The decoder needs to stop. Hand back the number of bytes we c
onsumed from |
661 // buffer minus 9 (the amount we consumed to read the header). | 656 // buffer minus 9 (the amount we consumed to read the header). |
662 setRemainingBytes(len + 9); | 657 setRemainingBytes(len + 9); |
663 GETN(9, GIFImageHeader); | 658 GETN(9, GIFImageHeader); |
664 return true; | 659 return true; |
665 } | 660 } |
666 | 661 |
667 addFrameIfNecessary(); | 662 addFrameIfNecessary(); |
668 GIFFrameContext* currentFrame = m_frames.last().get(); | 663 GIFFrameContext* currentFrame = m_frames.last().get(); |
669 | 664 |
670 currentFrame->setHeaderDefined(); | 665 currentFrame->setHeaderDefined(); |
| 666 |
| 667 // Work around more broken GIF files that have zero image width or |
| 668 // height. |
| 669 if (!height || !width) { |
| 670 height = m_screenHeight; |
| 671 width = m_screenWidth; |
| 672 if (!height || !width) |
| 673 return false; |
| 674 } |
671 currentFrame->setRect(xOffset, yOffset, width, height); | 675 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 currentFrame->setInterlaced(currentComponent[8] & 0x40); |
675 | 677 |
676 // Overlaying interlaced, transparent GIFs over | 678 // Overlaying interlaced, transparent GIFs over |
677 // existing image data using the Haeberli display hack | 679 // existing image data using the Haeberli display hack |
678 // requires saving the underlying image in order to | 680 // requires saving the underlying image in order to |
679 // avoid jaggies at the transparency edges. We are | 681 // avoid jaggies at the transparency edges. We are |
680 // unprepared to deal with that, so don't display such | 682 // unprepared to deal with that, so don't display such |
681 // images progressively. Which means only the first | 683 // images progressively. Which means only the first |
682 // frame can be progressively displayed. | 684 // frame can be progressively displayed. |
683 // FIXME: It is possible that a non-transparent frame | 685 // FIXME: It is possible that a non-transparent frame |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 rowIter = rowBuffer.begin(); | 793 rowIter = rowBuffer.begin(); |
792 rowsRemaining = m_frameContext->height(); | 794 rowsRemaining = m_frameContext->height(); |
793 | 795 |
794 // Clearing the whole suffix table lets us be more tolerant of bad data. | 796 // Clearing the whole suffix table lets us be more tolerant of bad data. |
795 for (int i = 0; i < clearCode; ++i) { | 797 for (int i = 0; i < clearCode; ++i) { |
796 suffix[i] = i; | 798 suffix[i] = i; |
797 suffixLength[i] = 1; | 799 suffixLength[i] = 1; |
798 } | 800 } |
799 return true; | 801 return true; |
800 } | 802 } |
OLD | NEW |