bool ImageSource::frameHasAlphaAtIndex(size_t index) { #ifdef ANDROID_ANIMATED_GIF if (m_decoder.m_gifDecoder) { if (!m_decoder.m_gifDecoder->supportsAlpha()) return false; RGBA32Buffer* buffer = m_decoder.m_gifDecoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return false; return buffer->hasAlpha(); } #else SkASSERT(0 == index); #endif if (NULL == m_decoder.m_image) return true; // if we're not sure, assume the worse-case const PrivateAndroidImageSourceRec& decoder = *m_decoder.m_image; // if we're 16bit, we know even without all the data available if (decoder.bitmap().getConfig() == SkBitmap::kRGB_565_Config) return false; if (!decoder.fAllDataReceived) return true; // if we're not sure, assume the worse-case return !decoder.bitmap().isOpaque(); }
bool ImageSource::frameIsCompleteAtIndex(size_t index) { if (!m_decoder) return false; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); return buffer && buffer->status() == RGBA32Buffer::FrameComplete; }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; return buffer->asNewNativeImage(); }
float ImageSource::frameDurationAtIndex(size_t index) { if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; return buffer->duration() / 1000.0f; }
bool ImageSource::frameHasAlphaAtIndex(size_t index) { if (!m_decoder || !m_decoder->supportsAlpha()) return false; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return false; return buffer->hasAlpha(); }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; IntRect imageRect = buffer->rect(); unsigned char* bytes = (unsigned char*)buffer->bytes().data(); long colorSize = buffer->bytes().size(); typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> PixelData; int width = size().width(); int height = size().height(); wxBitmap* bmp = new wxBitmap(width, height, 32); PixelData data(*bmp); int rowCounter = 0; long pixelCounter = 0; PixelData::Iterator p(data); PixelData::Iterator rowStart = p; // NB: It appears that the data is in BGRA format instead of RGBA format. // This code works properly on both ppc and intel, meaning the issue is // likely not an issue of byte order getting mixed up on different archs. for (long i = 0; i < buffer->bytes().size()*4; i+=4) { p.Red() = bytes[i+2]; p.Green() = bytes[i+1]; p.Blue() = bytes[i+0]; p.Alpha() = bytes[i+3]; p++; pixelCounter++; if ( (pixelCounter % width ) == 0 ) { rowCounter++; p = rowStart; p.MoveTo(data, 0, rowCounter); } } bmp->UseAlpha(); ASSERT(bmp->IsOk()); return bmp; }
bool ImageSource::frameIsCompleteAtIndex(size_t index) { #ifdef ANDROID_ANIMATED_GIF if (m_decoder.m_gifDecoder) { RGBA32Buffer* buffer = m_decoder.m_gifDecoder->frameBufferAtIndex(index); return buffer && buffer->status() == RGBA32Buffer::FrameComplete; } #else SkASSERT(0 == index); #endif return m_decoder.m_image && m_decoder.m_image->fAllDataReceived; }
RGBA32Buffer* BMPImageDecoder::frameBufferAtIndex(size_t index) { if (index) return 0; if (m_frameBufferCache.isEmpty()) m_frameBufferCache.resize(1); RGBA32Buffer* buffer = &m_frameBufferCache.first(); if (buffer->status() != RGBA32Buffer::FrameComplete) decode(false); return buffer; }
RGBA32Buffer* RxIImageDecoder::frameBufferAtIndex(size_t index) { if (index) return 0; RGBA32Buffer* frame = getUntouchedFrameBufferAtIndex(index); if (!frame) return 0; if (frame->status() != RGBA32Buffer::FrameComplete) decode(false); return frame; }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(), CAIRO_FORMAT_ARGB32, size().width(), buffer->height(), size().width()*4); }
float ImageSource::frameDurationAtIndex(size_t index) { if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; float duration = buffer->duration() / 1000.0f; // Follow other ports (and WinIE's) behavior to slow annoying ads that // specify a 0 duration. if (duration < 0.051f) return 0.100f; return duration; }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!m_decoder) return 0; // Note that the buffer can have NULL bytes even when it is marked as // non-empty. It seems "FrameEmpty" is only set before the frame has been // initialized. If it is decoded and it happens to be empty, it will be // marked as "FrameComplete" but will still have NULL bytes. RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; // Copy the bitmap. The pixel data is refcounted internally by SkBitmap, so // this doesn't cost much. return buffer->asNewNativeImage(); }
float ImageSource::frameDurationAtIndex(size_t index) { if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; // Many annoying ads specify a 0 duration to make an image flash as quickly // as possible. We follow WinIE's behavior and use a duration of 100 ms // for any frames that specify a duration of <= 50 ms. See // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for // more. const float duration = buffer->duration() / 1000.0f; return (duration < 0.051f) ? 0.100f : duration; }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!initialized()) return 0; if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; // Cairo does not like zero height images. // If we have a zero height image, just pretend we don't have enough data yet. if (!buffer->height()) return 0; /* <lab126> */ struct timespec startTime; KINDLE_BEGIN(Kindle_Debug_Perf) clock_gettime(CLOCK_MONOTONIC, &startTime); KINDLE_END() if (m_imageDitherType == USE_SIMPLE_ALGORITHM) { int imageWidth = size().width(); int imageHeight = buffer->height(); if(!dither_inited) for(int i=0; i<3333; i++) dither_buffer[i]=rand()%17; for (int n = 0; n < imageHeight; n++) { for (int m = 0; m < imageWidth; m++) { int rgb=buffer->bytes().data()[ (n*imageWidth) + m ]; int r = (rgb >> 16) & 0xff; int g = (rgb >> 8) & 0xff; int b = rgb & 0xff; int gray = (r == g && g == b) ? r : ((77 * r + 150 * g + 29 * b) >> 8); dither_index=(dither_index+1)%3333; int ngray=gray+dither_buffer[dither_index]; ngray-=ngray%17; if(ngray>0xff) ngray=0xff; buffer->bytes().data()[ (n*imageWidth) + m ] = (rgb&STRIP_ALPHA)|(ngray<<16)|(ngray<<8)|ngray; } } }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; DEBUG( "ImageSource::createFrameAtIndex() %i %i %i\n", size().width(), buffer->height(), buffer->bytes().size() ); os::Bitmap* pcBitmap = new os::Bitmap( size().width(), buffer->height(), os::CS_RGBA32 ); memcpy( pcBitmap->LockRaster(), reinterpret_cast<unsigned char*>(buffer->bytes().data()), ( buffer->height() * size().width() ) * 4 ); pcBitmap->UnlockRaster(); return( pcBitmap ); }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!initialized()) return 0; if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; // Cairo does not like zero height images. // If we have a zero height image, just pretend we don't have enough data yet. if (!size().height()) return 0; return buffer->asNewNativeImage(); }
SkBitmapRef* ImageSource::createFrameAtIndex(size_t index) { #ifdef ANDROID_ANIMATED_GIF if (m_decoder.m_gifDecoder) { RGBA32Buffer* buffer = m_decoder.m_gifDecoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; SkBitmap& bitmap = buffer->bitmap(); SkPixelRef* pixelRef = bitmap.pixelRef(); if (pixelRef) pixelRef->setURI(m_decoder.m_url); return new SkBitmapRef(bitmap); } #else SkASSERT(index == 0); #endif SkASSERT(m_decoder.m_image != NULL); m_decoder.m_image->ref(); return m_decoder.m_image; }
float ImageSource::frameDurationAtIndex(size_t index) { float duration = 0; #ifdef ANDROID_ANIMATED_GIF if (m_decoder.m_gifDecoder) { RGBA32Buffer* buffer = m_decoder.m_gifDecoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; duration = buffer->duration() / 1000.0f; } #else SkASSERT(index == 0); #endif // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify // a duration of <= 10 ms. See gfxImageFrame::GetTimeout in Gecko or Radar 4051389 for more. if (duration <= 0.010f) duration = 0.100f; return duration; }
NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { if (!initialized()) return 0; if (!m_decoder) return 0; RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; // Cairo does not like zero height images. // If we have a zero height image, just pretend we don't have enough data yet. if (!buffer->height()) return 0; return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(), CAIRO_FORMAT_ARGB32, size().width(), buffer->height(), size().width()*4); }
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; }