size_t GIFImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame)
{
    // We expect that after this call, we'll be asked to decode frames after
    // this one.  So we want to avoid clearing frames such that those requests
    // would force re-decoding from the beginning of the image.
    //
    // When |clearExceptFrame| is e.g. DisposeKeep, simply not clearing that
    // frame is sufficient, as the next frame will be based on it, and in
    // general future frames can't be based on anything previous.
    //
    // However, if this frame is DisposeOverwritePrevious, then subsequent
    // frames will depend on this frame's required previous frame.  In this
    // case, we need to preserve both this frame and that one.
    size_t clearExceptFrame2 = kNotFound;
    if (clearExceptFrame < m_frameBufferCache.size()) {
        const ImageFrame& frame = m_frameBufferCache[clearExceptFrame];
        if ((frame.getStatus() != ImageFrame::FrameEmpty) && (frame.getDisposalMethod() == ImageFrame::DisposeOverwritePrevious)) {
            clearExceptFrame2 = clearExceptFrame;
            clearExceptFrame = frame.requiredPreviousFrameIndex();
        }
    }

    // Now |clearExceptFrame| indicates the frame that future frames will
    // depend on.  But if decoding is skipping forward past intermediate frames,
    // this frame may be FrameEmpty.  So we need to keep traversing back through
    // the required previous frames until we find the nearest non-empty
    // ancestor.  Preserving that will minimize the amount of future decoding
    // needed.
    while ((clearExceptFrame < m_frameBufferCache.size()) && (m_frameBufferCache[clearExceptFrame].getStatus() == ImageFrame::FrameEmpty))
        clearExceptFrame = m_frameBufferCache[clearExceptFrame].requiredPreviousFrameIndex();
    return clearCacheExceptTwoFrames(clearExceptFrame, clearExceptFrame2);
}
Exemple #2
0
size_t ImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame) {
  // Don't clear if there are no frames or only one frame.
  if (m_frameBufferCache.size() <= 1)
    return 0;

  // We expect that after this call, we'll be asked to decode frames after this
  // one. So we want to avoid clearing frames such that those requests would
  // force re-decoding from the beginning of the image. There are two cases in
  // which preserving |clearCacheExcept| frame is not enough to avoid that:
  //
  // 1. |clearExceptFrame| is not yet sufficiently decoded to decode subsequent
  //    frames. We need the previous frame to sufficiently decode this frame.
  // 2. The disposal method of |clearExceptFrame| is DisposeOverwritePrevious.
  //    In that case, we need to keep the required previous frame in the cache
  //    to prevent re-decoding that frame when |clearExceptFrame| is disposed.
  //
  // If either 1 or 2 is true, store the required previous frame in
  // |clearExceptFrame2| so it won't be cleared.
  size_t clearExceptFrame2 = kNotFound;
  if (clearExceptFrame < m_frameBufferCache.size()) {
    const ImageFrame& frame = m_frameBufferCache[clearExceptFrame];
    if (!frameStatusSufficientForSuccessors(clearExceptFrame) ||
        frame.getDisposalMethod() == ImageFrame::DisposeOverwritePrevious)
      clearExceptFrame2 = frame.requiredPreviousFrameIndex();
  }

  // Now |clearExceptFrame2| indicates the frame that |clearExceptFrame|
  // depends on, as described above. But if decoding is skipping forward past
  // intermediate frames, this frame may be insufficiently decoded. So we need
  // to keep traversing back through the required previous frames until we find
  // the nearest ancestor that is sufficiently decoded. Preserving that will
  // minimize the amount of future decoding needed.
  while (clearExceptFrame2 < m_frameBufferCache.size() &&
         !frameStatusSufficientForSuccessors(clearExceptFrame2)) {
    clearExceptFrame2 =
        m_frameBufferCache[clearExceptFrame2].requiredPreviousFrameIndex();
  }

  return clearCacheExceptTwoFrames(clearExceptFrame, clearExceptFrame2);
}