📄 gifimagedecoder.cpp
字号:
/* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "GIFImageDecoder.h"#include "GIFImageReader.h"#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX)namespace WebCore {class GIFImageDecoderPrivate{public: GIFImageDecoderPrivate(GIFImageDecoder* decoder = 0) : m_reader(decoder) { m_readOffset = 0; } ~GIFImageDecoderPrivate() { m_reader.close(); } bool decode(const Vector<char>& data, GIFImageDecoder::GIFQuery query = GIFImageDecoder::GIFFullQuery, unsigned int haltFrame = -1) { return m_reader.read((const unsigned char*)data.data() + m_readOffset, data.size() - m_readOffset, query, haltFrame); } unsigned frameCount() const { return m_reader.images_count; } int repetitionCount() const { return m_reader.loop_count; } void setReadOffset(unsigned o) { m_readOffset = o; } bool isTransparent() const { return m_reader.frame_reader->is_transparent; } void getColorMap(unsigned char*& map, unsigned& size) const { if (m_reader.frame_reader->is_local_colormap_defined) { map = m_reader.frame_reader->local_colormap; size = (unsigned)m_reader.frame_reader->local_colormap_size; } else { map = m_reader.global_colormap; size = m_reader.global_colormap_size; } } unsigned frameXOffset() const { return m_reader.frame_reader->x_offset; } unsigned frameYOffset() const { return m_reader.frame_reader->y_offset; } unsigned frameWidth() const { return m_reader.frame_reader->width; } unsigned frameHeight() const { return m_reader.frame_reader->height; } int transparentPixel() const { return m_reader.frame_reader->tpixel; } unsigned duration() const { return m_reader.frame_reader->delay_time; }private: GIFImageReader m_reader; unsigned m_readOffset;};GIFImageDecoder::GIFImageDecoder(): m_frameCountValid(true), m_repetitionCount(cAnimationLoopOnce), m_reader(0){}GIFImageDecoder::~GIFImageDecoder(){ delete m_reader;}// Take the data and store it.void GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived){ if (m_failed) return; // Cache our new data. ImageDecoder::setData(data, allDataReceived); // Our frame count is now unknown. m_frameCountValid = false; // Create the GIF reader. if (!m_reader && !m_failed) m_reader = new GIFImageDecoderPrivate(this);}// Whether or not the size information has been decoded yet.bool GIFImageDecoder::isSizeAvailable() const{ // If we have pending data to decode, send it to the GIF reader now. if (!m_sizeAvailable && m_reader) { if (m_failed) return false; // The decoder will go ahead and aggressively consume everything up until the first // size is encountered. decode(GIFSizeQuery, 0); } return m_sizeAvailable;}// The total number of frames for the image. Will scan the image data for the answer// (without necessarily decoding all of the individual frames).int GIFImageDecoder::frameCount(){ // If the decoder had an earlier error, we will just return what we had decoded // so far. if (!m_frameCountValid) { // FIXME: Scanning all the data has O(n^2) behavior if the data were to come in really // slowly. Might be interesting to try to clone our existing read session to preserve // state, but for now we just crawl all the data. Note that this is no worse than what // ImageIO does on Mac right now (it also crawls all the data again). GIFImageDecoderPrivate reader; reader.decode(m_data->buffer(), GIFFrameCountQuery); m_frameCountValid = true; m_frameBufferCache.resize(reader.frameCount()); } return m_frameBufferCache.size();}// The number of repetitions to perform for an animation loop.int GIFImageDecoder::repetitionCount() const{ // This value can arrive at any point in the image data stream. Most GIFs // in the wild declare it near the beginning of the file, so it usually is // set by the time we've decoded the size, but (depending on the GIF and the // packets sent back by the webserver) not always. Our caller is // responsible for waiting until image decoding has finished to ask this if // it needs an authoritative answer. In the meantime, we should default to // "loop once". if (m_reader) { // Added wrinkle: ImageSource::clear() may destroy the reader, making // the result from the reader _less_ authoritative on future calls. To // detect this, the reader returns cLoopCountNotSeen (-2) instead of // cAnimationLoopOnce (-1) when its current incarnation hasn't actually // seen a loop count yet; in this case we return our previously-cached // value. const int repetitionCount = m_reader->repetitionCount(); if (repetitionCount != cLoopCountNotSeen) m_repetitionCount = repetitionCount; } return m_repetitionCount;}RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index){ if (index >= frameCount()) return 0; RGBA32Buffer& frame = m_frameBufferCache[index]; if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) // Decode this frame. decode(GIFFullQuery, index+1); return &frame;}void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame){ // In some cases, like if the decoder was destroyed while animating, we // can be asked to clear more frames than we currently have. if (m_frameBufferCache.isEmpty()) return; // Nothing to do. // The "-1" here is tricky. It does not mean that |clearBeforeFrame| is the // last frame we wish to preserve, but rather that we never want to clear // the very last frame in the cache: it's empty (so clearing it is // pointless), it's partial (so we don't want to clear it anyway), or the // cache could be enlarged with a future setData() call and it could be // needed to construct the next frame (see comments below). Callers can // always use ImageSource::clear(true, ...) to completely free the memory in // this case. clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1); const Vector<RGBA32Buffer>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame); // We need to preserve frames such that: // * We don't clear |end| // * We don't clear the frame we're currently decoding // * We don't clear any frame from which a future initFrameBuffer() call // will copy bitmap data // All other frames can be cleared. Because of the constraints on when // ImageSource::clear() can be called (see ImageSource.h), we're guaranteed // not to have non-empty frames after the frame we're currently decoding. // So, scan backwards from |end| as follows: // * If the frame is empty, we're still past any frames we care about. // * If the frame is complete, but is DisposeOverwritePrevious, we'll // skip over it in future initFrameBuffer() calls. We can clear it // unless it's |end|, and keep scanning. For any other disposal method, // stop scanning, as we've found the frame initFrameBuffer() will need // next. // * If the frame is partial, we're decoding it, so don't clear it; if it // has a disposal method other than DisposeOverwritePrevious, stop // scanning, as we'll only need this frame when decoding the next one. Vector<RGBA32Buffer>::iterator i(end); for (; (i != m_frameBufferCache.begin()) && ((i->status() == RGBA32Buffer::FrameEmpty) || (i->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious)); --i) { if ((i->status() == RGBA32Buffer::FrameComplete) && (i != end)) i->clear(); } // Now |i| holds the last frame we need to preserve; clear prior frames. for (Vector<RGBA32Buffer>::iterator j(m_frameBufferCache.begin()); j != i; ++j) { ASSERT(j->status() != RGBA32Buffer::FramePartial); if (j->status() != RGBA32Buffer::FrameEmpty) j->clear(); }}// Feed data to the GIF reader.void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame) const{ if (m_failed) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -