void GIFImageDecoder::decode(size_t index) { parse(GIFFrameCountQuery); if (failed()) return; updateAggressivePurging(index); Vector<size_t> framesToDecode; size_t frameToDecode = index; do { framesToDecode.append(frameToDecode); frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameIndex(); } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].getStatus() != ImageFrame::FrameComplete); for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { if (!m_reader->decode(*i)) { setFailed(); return; } if (m_purgeAggressively) clearCacheExceptFrame(*i); // We need more data to continue decoding. if (m_frameBufferCache[*i].getStatus() != ImageFrame::FrameComplete) break; } // It is also a fatal error if all data is received and we have decoded all // frames available but the file is truncated. if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_reader && !m_reader->parseCompleted()) setFailed(); }
bool WEBPImageDecoder::updateDemuxer() { if (failed()) return false; if (m_haveAlreadyParsedThisData) return true; m_haveAlreadyParsedThisData = true; const unsigned webpHeaderSize = 30; if (m_data->size() < webpHeaderSize) return false; // Await VP8X header so WebPDemuxPartial succeeds. WebPDemuxDelete(m_demux); m_consolidatedData = m_data->getAsSkData(); WebPData inputData = { reinterpret_cast<const uint8_t*>(m_consolidatedData->data()), m_consolidatedData->size()}; m_demux = WebPDemuxPartial(&inputData, &m_demuxState); if (!m_demux || (isAllDataReceived() && m_demuxState != WEBP_DEMUX_DONE)) { if (!m_demux) m_consolidatedData.reset(); return setFailed(); } ASSERT(m_demuxState > WEBP_DEMUX_PARSING_HEADER); if (!WebPDemuxGetI(m_demux, WEBP_FF_FRAME_COUNT)) return false; // Wait until the encoded image frame data arrives. if (!isDecodedSizeAvailable()) { int width = WebPDemuxGetI(m_demux, WEBP_FF_CANVAS_WIDTH); int height = WebPDemuxGetI(m_demux, WEBP_FF_CANVAS_HEIGHT); if (!setSize(width, height)) return setFailed(); m_formatFlags = WebPDemuxGetI(m_demux, WEBP_FF_FORMAT_FLAGS); if (!(m_formatFlags & ANIMATION_FLAG)) { m_repetitionCount = cAnimationNone; } else { // Since we have parsed at least one frame, even if partially, // the global animation (ANIM) properties have been read since // an ANIM chunk must precede the ANMF frame chunks. m_repetitionCount = WebPDemuxGetI(m_demux, WEBP_FF_LOOP_COUNT); // Repetition count is always <= 16 bits. ASSERT(m_repetitionCount == (m_repetitionCount & 0xffff)); if (!m_repetitionCount) m_repetitionCount = cAnimationLoopInfinite; // FIXME: Implement ICC profile support for animated images. m_formatFlags &= ~ICCP_FLAG; } if ((m_formatFlags & ICCP_FLAG) && !ignoresColorSpace()) readColorProfile(); } ASSERT(isDecodedSizeAvailable()); size_t frameCount = WebPDemuxGetI(m_demux, WEBP_FF_FRAME_COUNT); updateAggressivePurging(frameCount); return true; }