⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gifimagedecoder.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    m_failed = !m_reader->decode(m_data->buffer(), query, haltAtFrame);        if (m_failed) {        delete m_reader;        m_reader = 0;    }}// Callbacks from the GIF reader.void GIFImageDecoder::sizeNowAvailable(unsigned width, unsigned height){    m_size = IntSize(width, height);    m_sizeAvailable = true;}void GIFImageDecoder::decodingHalted(unsigned bytesLeft){    m_reader->setReadOffset(m_data->size() - bytesLeft);}void GIFImageDecoder::initFrameBuffer(unsigned frameIndex){    // Initialize the frame rect in our buffer.    IntRect frameRect(m_reader->frameXOffset(), m_reader->frameYOffset(),                      m_reader->frameWidth(), m_reader->frameHeight());    // Make sure the frameRect doesn't extend past the bottom-right of the buffer.    if (frameRect.right() > m_size.width())        frameRect.setWidth(m_size.width() - m_reader->frameXOffset());    if (frameRect.bottom() > m_size.height())        frameRect.setHeight(m_size.height() - m_reader->frameYOffset());    RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex];    buffer->setRect(frameRect);        if (frameIndex == 0) {        // This is the first frame, so we're not relying on any previous data.        prepEmptyFrameBuffer(buffer);    } else {        // The starting state for this frame depends on the previous frame's        // disposal method.        //        // Frames that use the DisposeOverwritePrevious method are effectively        // no-ops in terms of changing the starting state of a frame compared to        // the starting state of the previous frame, so skip over them.  (If the        // first frame specifies this method, it will get treated like        // DisposeOverwriteBgcolor below and reset to a completely empty image.)        const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];        ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete);        RGBA32Buffer::FrameDisposalMethod prevMethod =            prevBuffer->disposalMethod();        while ((frameIndex > 0) &&                (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) {            prevBuffer = &m_frameBufferCache[--frameIndex];            prevMethod = prevBuffer->disposalMethod();        }        if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) ||                (prevMethod == RGBA32Buffer::DisposeKeep)) {            // Preserve the last frame as the starting state for this frame.            buffer->bytes() = prevBuffer->bytes();            buffer->setHasAlpha(prevBuffer->hasAlpha());        } else {            // We want to clear the previous frame to transparent, without            // affecting pixels in the image outside of the frame.            const IntRect& prevRect = prevBuffer->rect();            if ((frameIndex == 0) ||                    prevRect.contains(IntRect(IntPoint(0, 0), m_size))) {                // Clearing the first frame, or a frame the size of the whole                // image, results in a completely empty image.                prepEmptyFrameBuffer(buffer);            } else {              // Copy the whole previous buffer, then clear just its frame.              buffer->bytes() = prevBuffer->bytes();              buffer->setHasAlpha(prevBuffer->hasAlpha());              for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {                  unsigned* const currentRow =                      buffer->bytes().data() + (y * m_size.width());                  for (int x = prevRect.x(); x < prevRect.right(); ++x)                      buffer->setRGBA(*(currentRow + x), 0, 0, 0, 0);              }              if ((prevRect.width() > 0) && (prevRect.height() > 0))                buffer->setHasAlpha(true);            }        }    }    // Update our status to be partially complete.    buffer->setStatus(RGBA32Buffer::FramePartial);    // Reset the alpha pixel tracker for this frame.    m_currentBufferSawAlpha = false;}void GIFImageDecoder::prepEmptyFrameBuffer(RGBA32Buffer* buffer) const{    buffer->bytes().resize(m_size.width() * m_size.height());    buffer->bytes().fill(0);    buffer->setHasAlpha(true);}void GIFImageDecoder::haveDecodedRow(unsigned frameIndex,                                     unsigned char* rowBuffer,   // Pointer to single scanline temporary buffer                                     unsigned char* rowEnd,                                     unsigned rowNumber,  // The row index                                     unsigned repeatCount,  // How many times to repeat the row                                     bool writeTransparentPixels){    // Initialize the frame if necessary.    RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];    if (buffer.status() == RGBA32Buffer::FrameEmpty)        initFrameBuffer(frameIndex);    // Do nothing for bogus data.    if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= m_size.height())      return;    unsigned colorMapSize;    unsigned char* colorMap;    m_reader->getColorMap(colorMap, colorMapSize);    if (!colorMap)        return;    // The buffers that we draw are the entire image's width and height, so a final output frame is    // width * height RGBA32 values in size.    //    // A single GIF frame, however, can be smaller than the entire image, i.e., it can represent some sub-rectangle    // within the overall image.  The rows we are decoding are within this    // sub-rectangle.  This means that if the GIF frame's sub-rectangle is (x,y,w,h) then row 0 is really row    // y, and each row goes from x to x+w.    unsigned dstPos = (m_reader->frameYOffset() + rowNumber) * m_size.width() + m_reader->frameXOffset();    unsigned* dst = buffer.bytes().data() + dstPos;    unsigned* dstEnd = dst + m_size.width() - m_reader->frameXOffset();    unsigned* currDst = dst;    unsigned char* currentRowByte = rowBuffer;        while (currentRowByte != rowEnd && currDst < dstEnd) {        if ((!m_reader->isTransparent() || *currentRowByte != m_reader->transparentPixel()) && *currentRowByte < colorMapSize) {            unsigned colorIndex = *currentRowByte * 3;            unsigned red = colorMap[colorIndex];            unsigned green = colorMap[colorIndex + 1];            unsigned blue = colorMap[colorIndex + 2];            RGBA32Buffer::setRGBA(*currDst, red, green, blue, 255);        } else {            m_currentBufferSawAlpha = true;            // We may or may not need to write transparent pixels to the buffer.            // If we're compositing against a previous image, it's wrong, and if            // we're writing atop a cleared, fully transparent buffer, it's            // unnecessary; but if we're decoding an interlaced gif and            // displaying it "Haeberli"-style, we must write these for passes            // beyond the first, or the initial passes will "show through" the            // later ones.            if (writeTransparentPixels)                RGBA32Buffer::setRGBA(*currDst, 0, 0, 0, 0);        }        currDst++;        currentRowByte++;    }    if (repeatCount > 1) {        // Copy the row |repeatCount|-1 times.        unsigned num = currDst - dst;        unsigned size = num * sizeof(unsigned);        unsigned width = m_size.width();        unsigned* end = buffer.bytes().data() + width * m_size.height();        currDst = dst + width;        for (unsigned i = 1; i < repeatCount; i++) {            if (currDst + num > end) // Protect against a buffer overrun from a bogus repeatCount.                break;            memcpy(currDst, dst, size);            currDst += width;        }    }    // Our partial height is rowNumber + 1, e.g., row 2 is the 3rd row, so that's a height of 3.    // Adding in repeatCount - 1 to rowNumber + 1 works out to just be rowNumber + repeatCount.    buffer.ensureHeight(rowNumber + repeatCount);}void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod){    // Initialize the frame if necessary.  Some GIFs insert do-nothing frames,    // in which case we never reach haveDecodedRow() before getting here.    RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];    if (buffer.status() == RGBA32Buffer::FrameEmpty)        initFrameBuffer(frameIndex);    buffer.ensureHeight(m_size.height());    buffer.setStatus(RGBA32Buffer::FrameComplete);    buffer.setDuration(frameDuration);    buffer.setDisposalMethod(disposalMethod);    if (!m_currentBufferSawAlpha) {        // The whole frame was non-transparent, so it's possible that the entire        // resulting buffer was non-transparent, and we can setHasAlpha(false).        if (buffer.rect().contains(IntRect(IntPoint(0, 0), m_size))) {            buffer.setHasAlpha(false);        } else if (frameIndex > 0) {            // Tricky case.  This frame does not have alpha only if everywhere            // outside its rect doesn't have alpha.  To know whether this is            // true, we check the start state of the frame -- if it doesn't have            // alpha, we're safe.            //            // First skip over prior DisposeOverwritePrevious frames (since they            // don't affect the start state of this frame) the same way we do in            // initFrameBuffer().            const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];            while ((frameIndex > 0) &&                    (prevBuffer->disposalMethod() ==                        RGBA32Buffer::DisposeOverwritePrevious))                prevBuffer = &m_frameBufferCache[--frameIndex];            // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then            // we can say we have no alpha if that frame had no alpha.  But            // since in initFrameBuffer() we already copied that frame's alpha            // state into the current frame's, we need do nothing at all here.            //            // The only remaining case is a DisposeOverwriteBgcolor frame.  If            // it had no alpha, and its rect is contained in the current frame's            // rect, we know the current frame has no alpha.            if ((prevBuffer->disposalMethod() ==                    RGBA32Buffer::DisposeOverwriteBgcolor) &&                    !prevBuffer->hasAlpha() &&                    buffer.rect().contains(prevBuffer->rect()))                buffer.setHasAlpha(false);        }    }}void GIFImageDecoder::gifComplete(){    if (m_reader)        m_repetitionCount = m_reader->repetitionCount();    delete m_reader;    m_reader = 0;}}#endif // PLATFORM(CAIRO)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -