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();
}
示例#2
0
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;
}