Exemplo n.º 1
0
void GIFImageDecoder::initFrameBuffer(RGBA32Buffer& buffer, 
                                      RGBA32Buffer* previousBuffer,
                                      bool compositeWithPreviousFrame)
{
    // Initialize the frame rect in our buffer.
    IntRect frameRect(m_reader->frameXOffset(), m_reader->frameYOffset(),
                      m_reader->frameWidth(), m_reader->frameHeight());
    buffer.setRect(frameRect);

    bool isSubRect = (frameRect.x() > 0 || frameRect.y() > 0 ||
                      frameRect.width() < m_size.width() ||
                      frameRect.height() < m_size.height());
    
    // Let's resize our buffer now to the correct width/height and then
    // initialize portions of it if needed.
    RGBA32Array& bytes = buffer.bytes();
        
    // If the disposal method of the previous frame said to stick around, then we need     
    // to copy that frame into our frame.  We also dont want to have any impact on
    // anything outside our frame's rect, so if we don't overlay the entire image,
    // then also composite with the previous frame.
    if (previousBuffer && (compositeWithPreviousFrame || isSubRect)) {
        bytes = previousBuffer->bytes();
        buffer.ensureHeight(m_size.height());
        buffer.setHasAlpha(previousBuffer->hasAlpha());
    }
    else // Resize to the width and height of the image.
        bytes.resize(m_size.width() * m_size.height());

    if (isSubRect) {
        // We need to go ahead and initialize the first frame to make sure
        // that areas outside the subrect start off transparent.
        if (!previousBuffer) {
            bytes.fill(0);
            buffer.setHasAlpha(true);
        } else if (!compositeWithPreviousFrame) {
            // Now this is an interesting case.  In the case where we fill 
            // the entire image, we effectively do a full clear of the image (and thus
            // don't have to initialize anything in our buffer).
            // 
            // However in the case where we only fill a piece of the image, two problems occur:
            // (1) We need to wipe out the area occupied by the previous frame, which
            // could also have been a subrect.
            // (2) Anything outside the previous frame's rect *and* outside our current
            // frame's rect should be left alone.
            // We have handled (2) by just initializing our buffer from the previous frame.
            // Our subrect will correctly overwrite the previous frame's contents as we
            // decode rows.  However that still leaves the problem of having to wipe out
            // the area occupied by the previous frame that does not overlap with
            // the new frame.
            if (previousBuffer->rect() != frameRect) {
                // We have to clear out the entire previous subframe.
                bool sawAlpha = buffer.hasAlpha();
                IntRect prevRect = previousBuffer->rect();
                unsigned end = prevRect.y() + prevRect.height();
                unsigned* src;
                for (unsigned i = prevRect.y(); i < end; i++) {
                    unsigned* curr = buffer.bytes().data() + (i * m_size.width() + prevRect.x());
                    unsigned* end = curr + prevRect.width();
                    while (curr != end) {
                        if (!sawAlpha) {
                            sawAlpha = true;
                            buffer.setHasAlpha(true);
                        }
                        RGBA32Buffer::setRGBA(*curr++, 0, 0, 0, 0);
                    }
                }
            }
        }
    }

    // Update our status to be partially complete.
    buffer.setStatus(RGBA32Buffer::FramePartial);
}
    bool decode(const Vector<char>& data, RxIImageDecoder::RxIFormat fmt)
    {
        int i = 0;
        int j = 0;
        bool result = false;
        RGBA32Buffer* frameBuffer = 0;
        unsigned char* rgbData = 0;

        if (!m_memoryManager)
            return false;

        m_memoryReader = new MemReader((unsigned char*)data.data(), data.size());

        // The rest of the code expects that the first 8 bytes has already been read.
        // The signature for these files is 8 bytes.

        m_memoryReader->SetOffset(8);


        switch (fmt) {
        case RxIImageDecoder::FormatRdi:
            m_rxi = RdiBirth(m_memoryManager, m_memoryReader);
            break;
        case RxIImageDecoder::FormatRgi:
            m_rxi = RgiBirth(m_memoryManager, m_memoryReader);
            break;
        case RxIImageDecoder::FormatRpi:
            m_rxi = RpiBirth(m_memoryManager, m_memoryReader);
            break;
        case RxIImageDecoder::FormatRwi:
            m_rxi = RwiBirth(m_memoryManager, m_memoryReader);
            break;
        case RxIImageDecoder::FormatUnknown:
            ASSERT_NOT_REACHED();
            break;
        }

        if (!m_rxi) {
            delete m_memoryReader;
            m_memoryReader = 0;
            return false;
        }
        m_format = fmt;

        switch (fmt) {
        case RxIImageDecoder::FormatRdi:
            result = RdiGetWH(m_rxi, &m_w, &m_h);
            break;
        case RxIImageDecoder::FormatRgi:
            result = RgiGetWH(m_rxi, &m_w, &m_h);
            break;
        case RxIImageDecoder::FormatRpi:
            result = RpiGetWH(m_rxi, &m_w, &m_h);
            break;
        case RxIImageDecoder::FormatRwi:
            result = RwiGetWH(m_rxi, &m_w, &m_h);
            break;
        case RxIImageDecoder::FormatUnknown:
            ASSERT_NOT_REACHED();
            break;
        }

        if (!result) {
            delete m_memoryReader;
            m_memoryReader = 0;
            return false;
        }

        // We can fill in the size now that the header is available.
        if (!m_decoder->setSize(m_w, m_h))
            return m_decoder->setFailed();

        frameBuffer = m_decoder->getUntouchedFrameBufferAtIndex(0);

        if (!frameBuffer) {
            delete m_memoryReader;
            m_memoryReader = 0;
            m_sizeInitialized = false;
            return false;
        }

        if (frameBuffer->status() == RGBA32Buffer::FrameEmpty) {
            if (!frameBuffer->setSize(m_w, m_h))
                return m_decoder->setFailed();
            frameBuffer->setStatus(RGBA32Buffer::FramePartial);

            if ( fmt == RxIImageDecoder::FormatRpi ) {
                // RPI format has alpha which we must support.
                frameBuffer->setHasAlpha(true);
            } else {
                frameBuffer->setHasAlpha(false);
            }
            // the frame always fills the entire image.
            frameBuffer->setRect(IntRect(IntPoint(0, 0), m_decoder->size()));
        }

        // note that we don't cleanup frameBuffer at all since we didn't allocate it.
        if ( fmt == RxIImageDecoder::FormatRgi ) {
            rgbData = (unsigned char*) malloc(m_w * m_h * 3);
        } else if ( fmt == RxIImageDecoder::FormatRpi ) {
            // extra channel is for alpha
            rgbData = (unsigned char*) malloc(m_w * m_h * 4);
        }

        MemWriter mw(m_w * m_h * 3);
        switch (fmt) {
        case RxIImageDecoder::FormatRdi:
            result = RdiGetRGB(m_rxi, &mw);
            break;
        case RxIImageDecoder::FormatRgi:
            result = RgiGetRGB(m_rxi, rgbData);
            break;
        case RxIImageDecoder::FormatRpi:
            result = RpiGetRGB(m_rxi, rgbData);
            break;
        case RxIImageDecoder::FormatRwi:
            result = RwiGetRGB(m_rxi, &mw);
            break;
        case RxIImageDecoder::FormatUnknown:
            ASSERT_NOT_REACHED();
            break;
        }

        if (result) {
            unsigned char* ptr = 0;
            if ((fmt == RxIImageDecoder::FormatRdi) || (fmt == RxIImageDecoder::FormatRwi))
                ptr = (unsigned char*)mw.GetBuffer();
            else
                ptr = rgbData;

            for (i = 0; i < m_h; ++i) {
                for (j = 0; j < m_w; ++j) {
                    unsigned char r, g, b;
                    unsigned char a = 0xFF;
                    r = *ptr;
                    ptr++;
                    g = *ptr;
                    ptr++;
                    b = *ptr;
                    ptr++;
                    if ( fmt == RxIImageDecoder::FormatRpi ) {
                        a = *ptr;
                        ptr++;
                    }
                    frameBuffer->setRGBA(j, i, r, g, b, a);
                }
            }
        }
        m_decoder->rxiComplete();

        // cleaning up
        free(rgbData);
        rgbData = 0;
        delete m_memoryReader;
        m_memoryReader = 0;
        m_sizeInitialized = false;

        switch (fmt) {
        case RxIImageDecoder::FormatRdi:
            RdiDeath(m_rxi);
            break;
        case RxIImageDecoder::FormatRgi:
            RgiDeath(m_rxi);
            break;
        case RxIImageDecoder::FormatRpi:
            RpiDeath(m_rxi);
            break;
        case RxIImageDecoder::FormatRwi:
            RwiDeath(m_rxi);
            break;
        case RxIImageDecoder::FormatUnknown:
            ASSERT_NOT_REACHED();
            break;
        }
        m_rxi = 0;
        return true;
    }