Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: Source/platform/image-decoders/gif/GIFImageReader.cpp

Issue 813943003: Fix handling of broken GIFs with weird frame sizes (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: nits Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 419 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 images are rendered. The
438 // individual images can be smaller than the screen size and located with an origin anywhere 438 // individual images can be smaller than the screen size and located with an origin anywhere
439 // within the screen. 439 // within the screen.
440 // Note that size is final only when the first frame is encountered.
440 m_screenWidth = GETINT16(currentComponent); 441 m_screenWidth = GETINT16(currentComponent);
441 m_screenHeight = GETINT16(currentComponent + 2); 442 m_screenHeight = GETINT16(currentComponent + 2);
442 443
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 ); 444 const size_t globalColorMapColors = 2 << (currentComponent[4] & 0x07 );
449 445
450 if ((currentComponent[4] & 0x80) && globalColorMapColors > 0) { /* g lobal map */ 446 if ((currentComponent[4] & 0x80) && globalColorMapColors > 0) { /* g lobal map */
451 m_globalColorMap.setTablePositionAndSize(dataPosition, globalCol orMapColors); 447 m_globalColorMap.setTablePositionAndSize(dataPosition, globalCol orMapColors);
452 GETN(BYTES_PER_COLORMAP_ENTRY * globalColorMapColors, GIFGlobalC olormap); 448 GETN(BYTES_PER_COLORMAP_ENTRY * globalColorMapColors, GIFGlobalC olormap);
453 break; 449 break;
454 } 450 }
455 451
456 GETN(1, GIFImageStart); 452 GETN(1, GIFImageStart);
457 break; 453 break;
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
625 unsigned height, width, xOffset, yOffset; 621 unsigned height, width, xOffset, yOffset;
626 622
627 /* Get image offsets, with respect to the screen origin */ 623 /* Get image offsets, with respect to the screen origin */
628 xOffset = GETINT16(currentComponent); 624 xOffset = GETINT16(currentComponent);
629 yOffset = GETINT16(currentComponent + 2); 625 yOffset = GETINT16(currentComponent + 2);
630 626
631 /* Get image width and height. */ 627 /* Get image width and height. */
632 width = GETINT16(currentComponent + 4); 628 width = GETINT16(currentComponent + 4);
633 height = GETINT16(currentComponent + 6); 629 height = GETINT16(currentComponent + 6);
634 630
635 /* Work around broken GIF files where the logical screen 631 // Work around broken GIF file where the first frame has size greate r than the
Peter Kasting 2015/01/08 06:56:18 Nit: files I also wouldn't mind wrapping the comm
Alpha Left Google 2015/01/12 22:12:49 Done.
636 * size has weird width or height. We assume that GIF87a 632 // "screen size".
Peter Kasting 2015/01/08 06:56:18 What about when subsequent frames have larger size
Alpha Left Google 2015/01/12 22:12:49 I added the std::max() code in 672 and 673 in the
637 * files don't contain animations.
638 */
639 if (currentFrameIsFirstFrame() 633 if (currentFrameIsFirstFrame()
640 && ((m_screenHeight < height) || (m_screenWidth < width) || (m_v ersion == 87))) { 634 && (m_screenHeight < yOffset + height || m_screenWidth < xOffset + width)) {
641 m_screenHeight = height; 635 m_screenHeight = std::max(m_screenHeight, yOffset + height);
642 m_screenWidth = width; 636 m_screenWidth = std::max(m_screenWidth, xOffset + width);
Peter Kasting 2015/01/08 06:56:18 This is a behavior change from the previous code i
Alpha Left Google 2015/01/12 22:12:49 The behavior changes unless the image is GIF87 and
643 xOffset = 0;
644 yOffset = 0;
645
646 // CALLBACK: Inform the decoderplugin of our size.
647 if (m_client && !m_client->setSize(m_screenWidth, m_screenHeight ))
648 return false;
649 } 637 }
650 638
651 // Work around more broken GIF files that have zero image width or h eight 639 // Inform the client of the final size.
652 if (!height || !width) { 640 if (!m_sizeFinal && m_client && !m_client->setSize(m_screenWidth, m_ screenHeight))
Peter Kasting 2015/01/08 06:56:18 Is it possible to have m_client null here but have
Alpha Left Google 2015/01/12 22:12:49 m_client is always non null. We shouldn't need to
653 height = m_screenHeight; 641 return false;
654 width = m_screenWidth; 642 m_sizeFinal = true;
655 if (!height || !width)
656 return false;
657 }
658 643
659 if (query == GIFImageDecoder::GIFSizeQuery) { 644 if (query == GIFImageDecoder::GIFSizeQuery) {
660 // The decoder needs to stop. Hand back the number of bytes we c onsumed from 645 // 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). 646 // buffer minus 9 (the amount we consumed to read the header).
662 setRemainingBytes(len + 9); 647 setRemainingBytes(len + 9);
663 GETN(9, GIFImageHeader); 648 GETN(9, GIFImageHeader);
664 return true; 649 return true;
665 } 650 }
666 651
667 addFrameIfNecessary(); 652 addFrameIfNecessary();
668 GIFFrameContext* currentFrame = m_frames.last().get(); 653 GIFFrameContext* currentFrame = m_frames.last().get();
669 654
670 currentFrame->setHeaderDefined(); 655 currentFrame->setHeaderDefined();
656
657 // Work around more broken GIF files that have zero image width or h eight.
658 if (!height || !width) {
659 height = m_screenHeight;
660 width = m_screenWidth;
661 if (!height || !width)
662 return false;
663 }
671 currentFrame->setRect(xOffset, yOffset, width, height); 664 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); 665 currentFrame->setInterlaced(currentComponent[8] & 0x40);
675 666
676 // Overlaying interlaced, transparent GIFs over 667 // Overlaying interlaced, transparent GIFs over
677 // existing image data using the Haeberli display hack 668 // existing image data using the Haeberli display hack
678 // requires saving the underlying image in order to 669 // requires saving the underlying image in order to
679 // avoid jaggies at the transparency edges. We are 670 // avoid jaggies at the transparency edges. We are
680 // unprepared to deal with that, so don't display such 671 // unprepared to deal with that, so don't display such
681 // images progressively. Which means only the first 672 // images progressively. Which means only the first
682 // frame can be progressively displayed. 673 // frame can be progressively displayed.
683 // FIXME: It is possible that a non-transparent frame 674 // FIXME: It is possible that a non-transparent frame
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 rowIter = rowBuffer.begin(); 782 rowIter = rowBuffer.begin();
792 rowsRemaining = m_frameContext->height(); 783 rowsRemaining = m_frameContext->height();
793 784
794 // Clearing the whole suffix table lets us be more tolerant of bad data. 785 // Clearing the whole suffix table lets us be more tolerant of bad data.
795 for (int i = 0; i < clearCode; ++i) { 786 for (int i = 0; i < clearCode; ++i) {
796 suffix[i] = i; 787 suffix[i] = i;
797 suffixLength[i] = 1; 788 suffixLength[i] = 1;
798 } 789 }
799 return true; 790 return true;
800 } 791 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698