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); }
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); }