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

📄 gifimagedecoder.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    m_failed = !m_reader->decode(m_data.get(), query, haltAtFrame);        if (m_failed) {        delete m_reader;        m_reader = 0;    }}// Callbacks from the GIF reader.bool GIFImageDecoder::sizeNowAvailable(unsigned width, unsigned height){    return setSize(width, height);}void GIFImageDecoder::decodingHalted(unsigned bytesLeft){    m_reader->setReadOffset(m_data->size() - bytesLeft);}bool 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() > size().width())        frameRect.setWidth(size().width() - m_reader->frameXOffset());    if (frameRect.bottom() > size().height())        frameRect.setHeight(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.        if (!prepEmptyFrameBuffer(buffer)) {            buffer->setStatus(RGBA32Buffer::FrameComplete);            m_failed = true;            return false;        }    } 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];        RGBA32Buffer::FrameDisposalMethod prevMethod =            prevBuffer->disposalMethod();        while ((frameIndex > 0)               && (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) {            prevBuffer = &m_frameBufferCache[--frameIndex];            prevMethod = prevBuffer->disposalMethod();        }        ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete);        if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) ||                (prevMethod == RGBA32Buffer::DisposeKeep)) {            // Preserve the last frame as the starting state for this frame.            buffer->copyBitmapData(*prevBuffer);            // This next line isn't currently necessary since the alpha state is            // currently carried along in the Skia bitmap data, but it's safe,            // future-proof, and parallel to the Cairo code.            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), 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->copyBitmapData(*prevBuffer);              // Unnecessary (but safe); see comments on the similar call above.              buffer->setHasAlpha(prevBuffer->hasAlpha());              SkBitmap& bitmap = buffer->bitmap();              for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {                  for (int x = prevRect.x(); x < prevRect.right(); ++x)                      buffer->setRGBA(bitmap.getAddr32(x, y), 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;    return true;}bool GIFImageDecoder::prepEmptyFrameBuffer(RGBA32Buffer* buffer) const{    if (!buffer->setSize(size().width(), size().height()))        return false;    // This next line isn't currently necessary since Skia's eraseARGB() sets    // this for us, but we do it for similar reasons to the setHasAlpha() calls    // in initFrameBuffer() above.    buffer->setHasAlpha(true);    return 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))        return;    // Do nothing for bogus data.    if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= 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) * size().width() + m_reader->frameXOffset();    unsigned* dst = buffer.bitmap().getAddr32(0, 0) + dstPos;    unsigned* dstEnd = dst + 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 data_size = num * sizeof(unsigned);        unsigned width = size().width();        unsigned* end = buffer.bitmap().getAddr32(0, 0) + width * 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, data_size);            currDst += width;        }    }}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))        return;    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), 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;}} // namespace WebCore

⌨️ 快捷键说明

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