Changeset 222910 in webkit


Ignore:
Timestamp:
Oct 5, 2017 7:00:05 AM (7 years ago)
Author:
magomez@igalia.com
Message:

[GTK][WPE] GIFImageDecoder never clears decoded frames even when told to do so
https://bugs.webkit.org/show_bug.cgi?id=177864

Reviewed by Carlos Garcia Campos.

Fix GIFImageDecoder::clearFrameBufferCache() so it really deletes decoded buffers, and modify
GIFImageDecoder to be able to decode frames that are not requested in the expected order.

Covered by existent tests.

  • platform/image-decoders/gif/GIFImageDecoder.cpp:

(WebCore::GIFImageDecoder::findFirstRequiredFrameToDecode):
(WebCore::GIFImageDecoder::frameBufferAtIndex):
(WebCore::GIFImageDecoder::clearFrameBufferCache):

  • platform/image-decoders/gif/GIFImageDecoder.h:
  • platform/image-decoders/gif/GIFImageReader.cpp:

(GIFImageReader::decode):

  • platform/image-decoders/gif/GIFImageReader.h:

(GIFImageReader::frameContext const):

Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r222908 r222910  
     12017-10-05  Miguel Gomez  <magomez@igalia.com>
     2
     3        [GTK][WPE] GIFImageDecoder never clears decoded frames even when told to do so
     4        https://bugs.webkit.org/show_bug.cgi?id=177864
     5
     6        Reviewed by Carlos Garcia Campos.
     7
     8        Fix GIFImageDecoder::clearFrameBufferCache() so it really deletes decoded buffers, and modify
     9        GIFImageDecoder to be able to decode frames that are not requested in the expected order.
     10
     11        Covered by existent tests.
     12
     13        * platform/image-decoders/gif/GIFImageDecoder.cpp:
     14        (WebCore::GIFImageDecoder::findFirstRequiredFrameToDecode):
     15        (WebCore::GIFImageDecoder::frameBufferAtIndex):
     16        (WebCore::GIFImageDecoder::clearFrameBufferCache):
     17        * platform/image-decoders/gif/GIFImageDecoder.h:
     18        * platform/image-decoders/gif/GIFImageReader.cpp:
     19        (GIFImageReader::decode):
     20        * platform/image-decoders/gif/GIFImageReader.h:
     21        (GIFImageReader::frameContext const):
     22
    1232017-10-05  Fujii Hironori  <Hironori.Fujii@sony.com>
    224
  • trunk/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp

    r222836 r222910  
    102102}
    103103
     104size_t GIFImageDecoder::findFirstRequiredFrameToDecode(size_t frameIndex)
     105{
     106    // The first frame doesn't depend on any other.
     107    if (!frameIndex)
     108        return 0;
     109
     110    for (size_t i = frameIndex; i > 0; --i) {
     111        ImageFrame& frame = m_frameBufferCache[i - 1];
     112
     113        // Frames with disposal method RestoreToPrevious are useless, skip them.
     114        if (frame.disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)
     115            continue;
     116
     117        // At this point the disposal method can be Unspecified, DoNotDispose or RestoreToBackground.
     118        // In every case, if the frame is complete we can start decoding the next one.
     119        if (frame.isComplete())
     120            return i;
     121
     122        // If the disposal method of this frame is RestoreToBackground and it fills the whole area,
     123        // the next frame's backing store is initialized to transparent, so we start decoding with it.
     124        if (frame.disposalMethod() == ImageFrame::DisposalMethod::RestoreToBackground) {
     125            // We cannot use frame.backingStore()->frameRect() here, because it has been cleared
     126            // when the frame was removed from the cache. We need to get the values from the
     127            // reader context.
     128            const auto* frameContext = m_reader->frameContext(i - 1);
     129            ASSERT(frameContext);
     130            IntRect frameRect(frameContext->xOffset, frameContext->yOffset, frameContext->width, frameContext->height);
     131            // We would need to scale frameRect and check whether it fills the whole scaledSize(). But
     132            // can check whether the original frameRect fills size() instead. If the frame fills the
     133            // whole area then it can be decoded without dependencies.
     134            if (frameRect.contains({ { }, size() }))
     135                return i;
     136        }
     137    }
     138
     139    return 0;
     140}
     141
    104142ImageFrame* GIFImageDecoder::frameBufferAtIndex(size_t index)
    105143{
     
    108146
    109147    ImageFrame& frame = m_frameBufferCache[index];
    110     if (!frame.isComplete())
    111         decode(index + 1, GIFFullQuery, isAllDataReceived());
     148    if (!frame.isComplete()) {
     149        for (auto i = findFirstRequiredFrameToDecode(index); i <= index; i++)
     150            decode(i + 1, GIFFullQuery, isAllDataReceived());
     151    }
     152
    112153    return &frame;
    113154}
     
    164205    for (Vector<ImageFrame>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
    165206        ASSERT(!j->isPartial());
    166         if (j->isInvalid())
     207        if (!j->isInvalid())
    167208            j->clear();
    168209    }
  • trunk/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.h

    r222836 r222910  
    6666    GIFImageDecoder(AlphaOption, GammaAndColorProfileOption);
    6767    void tryDecodeSize(bool allDataReceived) final { decode(0, GIFSizeQuery, allDataReceived); }
     68    size_t findFirstRequiredFrameToDecode(size_t);
    6869
    6970    // If the query is GIFFullQuery, decodes the image up to (but not
  • trunk/Source/WebCore/platform/image-decoders/gif/GIFImageReader.cpp

    r222836 r222910  
    366366    // Already decoded frames can be deleted from the cache and then they require to be decoded again, so
    367367    // the haltAtFrame value we receive here may be lower than m_currentDecodingFrame. In this case
    368     // we position m_currentDecodingFrame to haltAtFrame and decode from there.
     368    // we position m_currentDecodingFrame to haltAtFrame - 1 and decode from there.
    369369    // See bug https://bugs.webkit.org/show_bug.cgi?id=176089.
    370     m_currentDecodingFrame = std::min(m_currentDecodingFrame, static_cast<size_t>(haltAtFrame));
     370    m_currentDecodingFrame = std::min(m_currentDecodingFrame, static_cast<size_t>(haltAtFrame) - 1);
    371371
    372372    while (m_currentDecodingFrame < std::min(m_frames.size(), static_cast<size_t>(haltAtFrame))) {
  • trunk/Source/WebCore/platform/image-decoders/gif/GIFImageReader.h

    r206481 r222910  
    285285    }
    286286
     287    const GIFFrameContext* frameContext(size_t frame) const
     288    {
     289        return frame < m_frames.size() ? m_frames[frame].get() : nullptr;
     290    }
     291
    287292private:
    288293    bool parse(size_t dataPosition, size_t len, bool parseSizeOnly);
Note: See TracChangeset for help on using the changeset viewer.