Bug 716140 - Preallocate frames before going into a decoder. r=seth

--HG--
extra : rebase_source : 6445356bc4a01ac2890eca855103e58bda772095
This commit is contained in:
Joe Drew 2013-02-01 20:06:30 -05:00
parent c6cdce35eb
commit 7d7f4428f7
8 changed files with 96 additions and 86 deletions

View File

@ -139,7 +139,11 @@ nsBMPDecoder::FinishInternal()
nsIntRect r(0, 0, mBIH.width, GetHeight());
PostInvalidation(r);
PostFrameStop();
if (mUseAlphaData) {
PostFrameStop(RasterImage::kFrameHasAlpha);
} else {
PostFrameStop(RasterImage::kFrameOpaque);
}
PostDecodeDone();
}
}
@ -193,7 +197,6 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
if (!aCount || !mCurLine)
return;
nsresult rv;
if (mPos < BFH_INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
uint32_t toCopy = BFH_INTERNAL_LENGTH - mPos;
if (toCopy > aCount)
@ -308,34 +311,19 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
return;
}
uint32_t imageLength;
if (mBIH.compression == BI_RLE8 || mBIH.compression == BI_RLE4 ||
mBIH.compression == BI_ALPHABITFIELDS) {
rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height,
gfxASurface::ImageFormatARGB32,
(uint8_t**)&mImageData, &imageLength);
} else {
if (mBIH.compression != BI_RLE8 && mBIH.compression != BI_RLE4 &&
mBIH.compression != BI_ALPHABITFIELDS) {
// mRow is not used for RLE encoded images
mRow = (uint8_t*)moz_malloc((mBIH.width * mBIH.bpp) / 8 + 4);
// + 4 because the line is padded to a 4 bit boundary, but I don't want
// to make exact calculations here, that's unnecessary.
// Also, it compensates rounding error.
if (!mRow) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return;
}
if (mUseAlphaData) {
rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height,
gfxASurface::ImageFormatARGB32,
(uint8_t**)&mImageData, &imageLength);
} else {
rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height,
gfxASurface::ImageFormatRGB24,
(uint8_t**)&mImageData, &imageLength);
PostDataError();
return;
}
}
if (NS_FAILED(rv) || !mImageData) {
if (!mImageData) {
PostDecoderError(NS_ERROR_FAILURE);
return;
}
@ -343,11 +331,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
// Prepare for transparency
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
// Clear the image, as the RLE may jump over areas
memset(mImageData, 0, imageLength);
memset(mImageData, 0, mImageDataLength);
}
// Tell the superclass we're starting a frame
PostFrameStart();
}
if (mColors && mPos >= mLOH) {

View File

@ -315,7 +315,8 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
mContainedDecoder = new nsPNGDecoder(mImage);
mContainedDecoder->SetObserver(mObserver);
mContainedDecoder->SetSizeDecode(IsSizeDecode());
mContainedDecoder->InitSharedDecoder();
mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength,
mColormap, mColormapSize);
if (!WriteToContainedDecoder(mSignature, PNGSIGNATURESIZE)) {
return;
}
@ -384,7 +385,8 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
bmpDecoder->SetUseAlphaData(true);
mContainedDecoder->SetObserver(mObserver);
mContainedDecoder->SetSizeDecode(IsSizeDecode());
mContainedDecoder->InitSharedDecoder();
mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength,
mColormap, mColormapSize);
// The ICO format when containing a BMP does not include the 14 byte
// bitmap file header. To use the code of the BMP decoder we need to

View File

@ -37,7 +37,6 @@ nsIconDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
// We put this here to avoid errors about crossing initialization with case
// jumps on linux.
uint32_t bytesToRead = 0;
nsresult rv;
// Loop until the input data is gone
while (aCount > 0) {
@ -72,18 +71,11 @@ nsIconDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
break;
}
// Add the frame and signal
rv = mImage.EnsureFrame(0, 0, 0, mWidth, mHeight,
gfxASurface::ImageFormatARGB32,
&mImageData, &mImageDataLength);
if (NS_FAILED(rv)) {
PostDecoderError(rv);
if (!mImageData) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return;
}
// Tell the superclass we're starting a frame
PostFrameStart();
// Book Keeping
aBuffer++;
aCount--;

View File

@ -371,10 +371,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
/* Used to set up image size so arrays can be allocated */
jpeg_calc_output_dimensions(&mInfo);
uint32_t imagelength;
if (NS_FAILED(mImage.EnsureFrame(0, 0, 0, mInfo.image_width, mInfo.image_height,
gfxASurface::ImageFormatRGB24,
&mImageData, &imagelength))) {
if (!mImageData) {
mState = JPEG_ERROR;
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
@ -386,9 +383,6 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
(" JPEGDecoderAccounting: nsJPEGDecoder::Write -- created image frame with %ux%u pixels",
mInfo.image_width, mInfo.image_height));
// Tell the superclass we're starting a frame
PostFrameStart();
mState = JPEG_START_DECOMPRESS;
}
@ -542,7 +536,7 @@ nsJPEGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
void
nsJPEGDecoder::NotifyDone()
{
PostFrameStop();
PostFrameStop(RasterImage::kFrameOpaque);
PostDecodeDone();
}

View File

@ -174,12 +174,7 @@ nsWBMPDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
return;
}
// Add the frame and signal
nsresult rv = mImage.EnsureFrame(0, 0, 0, mWidth, mHeight,
gfxASurface::ImageFormatRGB24,
(uint8_t**)&mImageData, &mImageDataLength);
if (NS_FAILED(rv) || !mImageData) {
if (!mImageData) {
PostDecoderError(NS_ERROR_FAILURE);
mState = DecodingFailed;
return;
@ -193,9 +188,6 @@ nsWBMPDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
return;
}
// Tell the superclass we're starting a frame
PostFrameStart();
mState = DecodingImageData;
} else if (heightReadResult == IntParseFailed) {

View File

@ -52,16 +52,24 @@ Decoder::Init()
// Implementation-specific initialization
InitInternal();
mInitialized = true;
}
// Initializes a decoder whose image and observer is already being used by a
// parent decoder
void
Decoder::InitSharedDecoder()
Decoder::InitSharedDecoder(uint8_t* imageData, uint32_t imageDataLength,
uint32_t* colormap, uint32_t colormapSize)
{
// No re-initializing
NS_ABORT_IF_FALSE(!mInitialized, "Can't re-initialize a decoder!");
NS_ABORT_IF_FALSE(mObserver, "Need an observer!");
mImageData = imageData;
mImageDataLength = imageDataLength;
mColormap = colormap;
mColormapSize = colormapSize;
// Implementation-specific initialization
InitInternal();
@ -81,35 +89,26 @@ Decoder::Write(const char* aBuffer, uint32_t aCount)
if (HasDataError())
return;
nsresult rv = NS_OK;
// Preallocate a frame if we've been asked to.
if (mNeedsNewFrame) {
rv = AllocateFrame();
if (NS_FAILED(rv)) {
PostDataError();
return;
}
}
// Pass the data along to the implementation
WriteInternal(aBuffer, aCount);
// If the decoder told us that it needs a new frame to proceed, let's create
// one and call it again.
while (mNeedsNewFrame && !HasDataError()) {
nsresult rv;
if (mNewFrameData.mPaletteDepth) {
rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX,
mNewFrameData.mOffsetY, mNewFrameData.mWidth,
mNewFrameData.mHeight, mNewFrameData.mFormat,
mNewFrameData.mPaletteDepth,
&mImageData, &mImageDataLength,
&mColormap, &mColormapSize);
} else {
rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX,
mNewFrameData.mOffsetY, mNewFrameData.mWidth,
mNewFrameData.mHeight, mNewFrameData.mFormat,
&mImageData, &mImageDataLength);
}
// Release our new frame data before talking to anyone else so they can
// tell us if they need yet another.
mNeedsNewFrame = false;
nsresult rv = AllocateFrame();
if (NS_SUCCEEDED(rv)) {
// We've now created our frame, so be sure we keep track of it correctly.
PostFrameStart();
// Tell the decoder to use the data it saved when it asked for a new frame.
WriteInternal(nullptr, 0);
} else {
@ -189,6 +188,37 @@ Decoder::FinishSharedDecoder()
}
}
nsresult
Decoder::AllocateFrame()
{
MOZ_ASSERT(mNeedsNewFrame);
nsresult rv;
if (mNewFrameData.mPaletteDepth) {
rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX,
mNewFrameData.mOffsetY, mNewFrameData.mWidth,
mNewFrameData.mHeight, mNewFrameData.mFormat,
mNewFrameData.mPaletteDepth,
&mImageData, &mImageDataLength,
&mColormap, &mColormapSize);
} else {
rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX,
mNewFrameData.mOffsetY, mNewFrameData.mWidth,
mNewFrameData.mHeight, mNewFrameData.mFormat,
&mImageData, &mImageDataLength);
}
if (NS_SUCCEEDED(rv)) {
PostFrameStart();
}
// Mark ourselves as not needing another frame before talking to anyone else
// so they can tell us if they need yet another.
mNeedsNewFrame = false;
return rv;
}
void
Decoder::FlushInvalidations()
{

View File

@ -34,7 +34,8 @@ public:
*
* Notifications Sent: TODO
*/
void InitSharedDecoder();
void InitSharedDecoder(uint8_t* imageData, uint32_t imageDataLength,
uint32_t* colormap, uint32_t colormapSize);
/**
* Writes data to the decoder.
@ -134,6 +135,18 @@ public:
ImageMetadata& GetImageMetadata() { return mImageMetadata; }
// Tell the decoder infrastructure to allocate a frame. By default, frame 0
// is created as an ARGB frame with no offset and with size width * height.
// If decoders need something different, they must ask for it.
// This is called by decoders when they need a new frame. These decoders
// must then save the data they have been sent but not yet processed and
// return from WriteInternal. When the new frame is created, WriteInternal
// will be called again with nullptr and 0 as arguments.
void NeedNewFrame(uint32_t frameNum, uint32_t x_offset, uint32_t y_offset,
uint32_t width, uint32_t height,
gfxASurface::gfxImageFormat format,
uint8_t palette_depth = 0);
protected:
/*
@ -184,14 +197,9 @@ protected:
void PostDataError();
void PostDecoderError(nsresult aFailCode);
// This is called by decoders when they need a new frame. These decoders
// must then save the data they have been sent but not yet processed and
// return from WriteInternal. When the new frame is created, WriteInternal
// will be called again with nullptr and 0 as arguments.
void NeedNewFrame(uint32_t frameNum, uint32_t x_offset, uint32_t y_offset,
uint32_t width, uint32_t height,
gfxASurface::gfxImageFormat format,
uint8_t palette_depth = 0);
// Try to allocate a frame as described in mNewFrameData and return the
// status code from that attempt. Clears mNewFrameData.
nsresult AllocateFrame();
/*
* Member variables.

View File

@ -2618,6 +2618,13 @@ RasterImage::InitDecoder(bool aDoSizeDecode)
mDecoder->SetObserver(mDecodeRequest->mStatusTracker->GetDecoderObserver());
mDecoder->SetSizeDecode(aDoSizeDecode);
mDecoder->SetDecodeFlags(mFrameDecodeFlags);
if (!aDoSizeDecode) {
// We already have the size; tell the decoder so it can preallocate a
// frame. By default, we create an ARGB frame with no offset. If decoders
// need a different type, they need to ask for it themselves.
mDecoder->NeedNewFrame(0, 0, 0, mSize.width, mSize.height,
gfxASurface::ImageFormatARGB32);
}
mDecoder->Init();
CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());