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; }