# HG changeset patch # User Rafał Mużyło # Parent 69e253891ca3839b6d4b8f5cb7c0e6950bb66902 Fix animated gif flickering bug 597174 diff --git a/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp --- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp +++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp @@ -197,30 +197,29 @@ static NS_METHOD ReadDataOut(nsIInputStr } // Push any new rows according to mCurrentPass/mLastFlushedPass and // mCurrentRow/mLastFlushedRow. Note: caller is responsible for // updating mlastFlushed{Row,Pass}. nsresult nsGIFDecoder2::FlushImageData(PRUint32 fromRow, PRUint32 rows) { - nsIntRect r(0, fromRow, mGIFStruct.width, rows); + nsIntRect r(mGIFStruct.x_offset, mGIFStruct.y_offset + fromRow, mGIFStruct.width, rows); // Update image nsresult rv = mImageContainer->FrameUpdated(mGIFStruct.images_decoded, r); if (NS_FAILED(rv)) { return rv; } // Offset to the frame position // Only notify observer(s) for first frame if (!mGIFStruct.images_decoded && mObserver) { PRUint32 imgCurFrame; mImageContainer->GetCurrentFrameIndex(&imgCurFrame); - r.y += mGIFStruct.y_offset; mObserver->OnDataAvailable(nsnull, imgCurFrame == PRUint32(mGIFStruct.images_decoded), &r); } return NS_OK; } nsresult nsGIFDecoder2::FlushImageData() { diff --git a/modules/libpr0n/src/imgContainer.cpp b/modules/libpr0n/src/imgContainer.cpp --- a/modules/libpr0n/src/imgContainer.cpp +++ b/modules/libpr0n/src/imgContainer.cpp @@ -415,16 +415,18 @@ nsresult imgContainer::InternalAddFrameH nsAutoPtr frame(aFrame); if (paletteData && paletteLength) frame->GetPaletteData(paletteData, paletteLength); frame->GetImageData(imageData, imageLength); + frame->LockImageData(); + mFrames.InsertElementAt(framenum, frame.forget()); mNumFrames++; return NS_OK; } nsresult imgContainer::InternalAddFrame(PRUint32 framenum, PRInt32 aX, PRInt32 aY, @@ -440,16 +442,21 @@ nsresult imgContainer::InternalAddFrame( return NS_ERROR_INVALID_ARG; nsAutoPtr frame(new imgFrame()); NS_ENSURE_TRUE(frame, NS_ERROR_OUT_OF_MEMORY); nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth); NS_ENSURE_SUCCESS(rv, rv); + if (mFrames.Length() > 0) { + imgFrame *prevframe = mFrames.ElementAt(mFrames.Length() - 1); + prevframe->UnlockImageData(); + } + if (mFrames.Length() == 0) { return InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength, paletteData, paletteLength); } if (mFrames.Length() == 1) { // Since we're about to add our second frame, initialize animation stuff if (!ensureAnimExists()) diff --git a/modules/libpr0n/src/imgFrame.cpp b/modules/libpr0n/src/imgFrame.cpp --- a/modules/libpr0n/src/imgFrame.cpp +++ b/modules/libpr0n/src/imgFrame.cpp @@ -152,16 +152,17 @@ imgFrame::imgFrame() : mBlendMethod(1), /* imgIContainer::kBlendOver */ mSinglePixel(PR_FALSE), mNeverUseDeviceSurface(PR_FALSE), mFormatChanged(PR_FALSE), mCompositingFailed(PR_FALSE) #ifdef USE_WIN_SURFACE , mIsDDBSurface(PR_FALSE) #endif + , mLocked(PR_FALSE) { static PRBool hasCheckedOptimize = PR_FALSE; if (!hasCheckedOptimize) { if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) { gDisableOptimize = PR_TRUE; } hasCheckedOptimize = PR_TRUE; } @@ -413,18 +414,17 @@ void imgFrame::Draw(gfxContext *aContext nsRefPtr surface; gfxImageSurface::gfxImageFormat format; NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(), "We must be allowed to sample *some* source pixels!"); PRBool doTile = !imageRect.Contains(sourceRect); if (doPadding || doPartialDecode) { - gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height) + - gfxPoint(aPadding.left, aPadding.top); + gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height); if (!doTile && !mSinglePixel) { // Not tiling, and we have a surface, so we can account for // padding and/or a partial decode just by twiddling parameters. // First, update our user-space fill rect. sourceRect = sourceRect.Intersect(available); gfxMatrix imageSpaceToUserSpace = userSpaceToImageSpace; imageSpaceToUserSpace.Invert(); @@ -708,17 +708,17 @@ nsresult imgFrame::ImageUpdated(const ns mem->IsLowMemory(&lowMemory); if (lowMemory) return NS_ERROR_OUT_OF_MEMORY; mDecoded.UnionRect(mDecoded, aUpdateRect); // clamp to bounds, in case someone sends a bogus updateRect (I'm looking at // you, gif decoder) - nsIntRect boundsRect(0, 0, mSize.width, mSize.height); + nsIntRect boundsRect(mOffset, mSize); mDecoded.IntersectRect(mDecoded, boundsRect); #ifdef XP_MACOSX if (mQuartzSurface) mQuartzSurface->Flush(); #endif return NS_OK; } @@ -806,17 +806,23 @@ void imgFrame::GetPaletteData(PRUint32 * *aPalette = (PRUint32 *) mPalettedImageData; *length = PaletteDataLength(); } } nsresult imgFrame::LockImageData() { if (mPalettedImageData) - return NS_OK; + return NS_ERROR_NOT_AVAILABLE; + + NS_ABORT_IF_FALSE(!mLocked, "Trying to lock already locked image data."); + if (mLocked) { + return NS_ERROR_FAILURE; + } + mLocked = PR_TRUE; if ((mOptSurface || mSinglePixel) && !mImageSurface) { // Recover the pixels mImageSurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height), gfxImageSurface::ImageFormatARGB32); if (!mImageSurface || mImageSurface->CairoStatus()) return NS_ERROR_OUT_OF_MEMORY; @@ -832,23 +838,35 @@ nsresult imgFrame::LockImageData() #ifdef USE_WIN_SURFACE mWinSurface = nsnull; #endif #ifdef XP_MACOSX mQuartzSurface = nsnull; #endif } + if (mImageSurface) + mImageSurface->Flush(); + return NS_OK; } nsresult imgFrame::UnlockImageData() { if (mPalettedImageData) - return NS_OK; + return NS_ERROR_NOT_AVAILABLE; + + NS_ABORT_IF_FALSE(mLocked, "Unlocking an unlocked image!"); + if (!mLocked) { + return NS_ERROR_FAILURE; + } + mLocked = PR_FALSE; + + if (mImageSurface) + mImageSurface->MarkDirty(); #ifdef XP_MACOSX if (mQuartzSurface) mQuartzSurface->Flush(); #endif return NS_OK; } @@ -895,17 +913,17 @@ PRInt32 imgFrame::GetBlendMethod() const void imgFrame::SetBlendMethod(PRInt32 aBlendMethod) { mBlendMethod = (PRInt8)aBlendMethod; } PRBool imgFrame::ImageComplete() const { - return mDecoded == nsIntRect(0, 0, mSize.width, mSize.height); + return mDecoded == nsIntRect(mOffset, mSize); } // A hint from the image decoders that this image has no alpha, even // though we created is ARGB32. This changes our format to RGB24, // which in turn will cause us to Optimize() to RGB24. Has no effect // after Optimize() is called, though in all cases it will be just a // performance win -- the pixels are still correct and have the A byte // set to 0xff. diff --git a/modules/libpr0n/src/imgFrame.h b/modules/libpr0n/src/imgFrame.h --- a/modules/libpr0n/src/imgFrame.h +++ b/modules/libpr0n/src/imgFrame.h @@ -167,16 +167,17 @@ private: // data gfxASurface::gfxImageFormat mFormat; PRInt8 mPaletteDepth; PRInt8 mBlendMethod; PRPackedBool mSinglePixel; PRPackedBool mNeverUseDeviceSurface; PRPackedBool mFormatChanged; PRPackedBool mCompositingFailed; + PRPackedBool mLocked; #ifdef XP_WIN PRPackedBool mIsDDBSurface; #endif }; #endif /* imgFrame_h */