From ae00f4faf942cb3604d7b5010eda4dc754d1bf15 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Fri, 22 Aug 2014 13:49:54 -0700 Subject: [PATCH] Bug 1054076 - Make imgFrame reference counted. r=tn --- image/decoders/nsGIFDecoder2.cpp | 32 ++++++----- image/decoders/nsPNGDecoder.cpp | 15 ++--- image/src/Decoder.cpp | 8 ++- image/src/Decoder.h | 8 ++- image/src/FrameAnimator.cpp | 13 +++-- image/src/FrameBlender.cpp | 72 ++++++++++++------------ image/src/FrameBlender.h | 6 +- image/src/FrameSequence.cpp | 10 ++-- image/src/FrameSequence.h | 63 +++++++++++++-------- image/src/RasterImage.cpp | 97 ++++++++++++++++---------------- image/src/RasterImage.h | 14 ++--- image/src/imgFrame.cpp | 25 ++++++++ image/src/imgFrame.h | 12 +++- 13 files changed, 217 insertions(+), 158 deletions(-) diff --git a/image/decoders/nsGIFDecoder2.cpp b/image/decoders/nsGIFDecoder2.cpp index 8198086ecd3..e3fd035dcf0 100644 --- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -174,22 +174,24 @@ void nsGIFDecoder2::BeginImageFrame(uint16_t aDepth) NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset, mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height, format, aDepth); - } - - // Our first full frame is automatically created by the image decoding - // infrastructure. Just use it as long as it matches up. - else if (!GetCurrentFrame()->GetRect().IsEqualEdges(nsIntRect(mGIFStruct.x_offset, - mGIFStruct.y_offset, - mGIFStruct.width, - mGIFStruct.height))) { - // Regardless of depth of input, image is decoded into 24bit RGB - NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset, - mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height, - format); } else { - // Our preallocated frame matches up, with the possible exception of alpha. - if (format == gfx::SurfaceFormat::B8G8R8X8) { - GetCurrentFrame()->SetHasNoAlpha(); + nsRefPtr currentFrame = GetCurrentFrame(); + + // Our first full frame is automatically created by the image decoding + // infrastructure. Just use it as long as it matches up. + if (!currentFrame->GetRect().IsEqualEdges(nsIntRect(mGIFStruct.x_offset, + mGIFStruct.y_offset, + mGIFStruct.width, + mGIFStruct.height))) { + // Regardless of depth of input, image is decoded into 24bit RGB + NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset, + mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height, + format); + } else { + // Our preallocated frame matches up, with the possible exception of alpha. + if (format == gfx::SurfaceFormat::B8G8R8X8) { + currentFrame->SetHasNoAlpha(); + } } } diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index 6a9fb68ddeb..665698590fd 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -145,20 +145,19 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset, // Our first full frame is automatically created by the image decoding // infrastructure. Just use it as long as it matches up. MOZ_ASSERT(HasSize()); - if (mNumFrames != 0 || - !GetCurrentFrame()->GetRect().IsEqualEdges(nsIntRect(x_offset, y_offset, width, height))) { + nsIntRect neededRect(x_offset, y_offset, width, height); + nsRefPtr currentFrame = GetCurrentFrame(); + if (mNumFrames != 0 || !currentFrame->GetRect().IsEqualEdges(neededRect)) { NeedNewFrame(mNumFrames, x_offset, y_offset, width, height, format); } else if (mNumFrames == 0) { // Our preallocated frame matches up, with the possible exception of alpha. if (format == gfx::SurfaceFormat::B8G8R8X8) { - GetCurrentFrame()->SetHasNoAlpha(); + currentFrame->SetHasNoAlpha(); } } - mFrameRect.x = x_offset; - mFrameRect.y = y_offset; - mFrameRect.width = width; - mFrameRect.height = height; + mFrameRect = neededRect; + mFrameHasNoAlpha = true; PR_LOG(GetPNGDecoderAccountingLog(), PR_LOG_DEBUG, ("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created " @@ -166,8 +165,6 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset, width, height, &mImage)); - mFrameHasNoAlpha = true; - #ifdef PNG_APNG_SUPPORTED if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) { mAnimInfo = AnimFrameInfo(mPNG, mInfo); diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp index 3db3d7b7dcb..4694958b0cc 100644 --- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -204,19 +204,21 @@ Decoder::AllocateFrame() MOZ_ASSERT(NS_IsMainThread()); nsresult rv; - imgFrame* frame = nullptr; + nsRefPtr frame; if (mNewFrameData.mPaletteDepth) { rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX, mNewFrameData.mOffsetY, mNewFrameData.mWidth, mNewFrameData.mHeight, mNewFrameData.mFormat, mNewFrameData.mPaletteDepth, &mImageData, &mImageDataLength, - &mColormap, &mColormapSize, &frame); + &mColormap, &mColormapSize, + getter_AddRefs(frame)); } else { rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX, mNewFrameData.mOffsetY, mNewFrameData.mWidth, mNewFrameData.mHeight, mNewFrameData.mFormat, - &mImageData, &mImageDataLength, &frame); + &mImageData, &mImageDataLength, + getter_AddRefs(frame)); } if (NS_SUCCEEDED(rv)) { diff --git a/image/src/Decoder.h b/image/src/Decoder.h index ff5c6ebec5a..6527ca9b186 100644 --- a/image/src/Decoder.h +++ b/image/src/Decoder.h @@ -171,7 +171,11 @@ public: // status code from that attempt. Clears mNewFrameData. virtual nsresult AllocateFrame(); - imgFrame* GetCurrentFrame() const { return mCurrentFrame; } + already_AddRefed GetCurrentFrame() const + { + nsRefPtr frame = mCurrentFrame; + return frame.forget(); + } protected: @@ -230,7 +234,7 @@ protected: * */ RasterImage &mImage; - imgFrame* mCurrentFrame; + nsRefPtr mCurrentFrame; RefPtr mObserver; ImageMetadata mImageMetadata; diff --git a/image/src/FrameAnimator.cpp b/image/src/FrameAnimator.cpp index ef866ecdcfb..be5ea7db6f0 100644 --- a/image/src/FrameAnimator.cpp +++ b/image/src/FrameAnimator.cpp @@ -85,13 +85,12 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime) int32_t timeout = 0; RefreshResult ret; + nsRefPtr nextFrame = mFrameBlender.RawGetFrame(nextFrameIndex); // If we're done decoding, we know we've got everything we're going to get. // If we aren't, we only display fully-downloaded frames; everything else // gets delayed. - bool canDisplay = mDoneDecoding || - (mFrameBlender.RawGetFrame(nextFrameIndex) && - mFrameBlender.RawGetFrame(nextFrameIndex)->ImageComplete()); + bool canDisplay = mDoneDecoding || (nextFrame && nextFrame->ImageComplete()); if (!canDisplay) { // Uh oh, the frame we want to show is currently being decoded (partial) @@ -138,10 +137,14 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime) ret.dirtyRect = mFirstFrameRefreshArea; } else { // Change frame + if (nextFrameIndex != currentFrameIndex + 1) { + nextFrame = mFrameBlender.RawGetFrame(nextFrameIndex); + } + if (!mFrameBlender.DoBlend(&ret.dirtyRect, currentFrameIndex, nextFrameIndex)) { // something went wrong, move on to next NS_WARNING("FrameAnimator::AdvanceFrame(): Compositing of frame failed"); - mFrameBlender.RawGetFrame(nextFrameIndex)->SetCompositingFailed(true); + nextFrame->SetCompositingFailed(true); mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(); mCurrentAnimationFrameIndex = nextFrameIndex; @@ -149,7 +152,7 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime) return ret; } - mFrameBlender.RawGetFrame(nextFrameIndex)->SetCompositingFailed(false); + nextFrame->SetCompositingFailed(false); } mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(); diff --git a/image/src/FrameBlender.cpp b/image/src/FrameBlender.cpp index 64c188c0b45..ed7779ebbb6 100644 --- a/image/src/FrameBlender.cpp +++ b/image/src/FrameBlender.cpp @@ -35,27 +35,27 @@ FrameBlender::GetFrameSequence() return seq.forget(); } -imgFrame* +already_AddRefed FrameBlender::GetFrame(uint32_t framenum) const { if (!mAnim) { NS_ASSERTION(framenum == 0, "Don't ask for a frame > 0 if we're not animated!"); - return mFrames->GetFrame(0); + return mFrames->GetFrame(0).GetFrame(); } - if (mAnim->lastCompositedFrameIndex == int32_t(framenum)) - return mAnim->compositingFrame; - return mFrames->GetFrame(framenum); + if (mAnim->lastCompositedFrameIndex == int32_t(framenum)) { + return mAnim->compositingFrame.GetFrame(); + } + return mFrames->GetFrame(framenum).GetFrame(); } -imgFrame* +already_AddRefed FrameBlender::RawGetFrame(uint32_t framenum) const { if (!mAnim) { NS_ASSERTION(framenum == 0, "Don't ask for a frame > 0 if we're not animated!"); - return mFrames->GetFrame(0); + return mFrames->GetFrame(0).GetFrame(); } - - return mFrames->GetFrame(framenum); + return mFrames->GetFrame(framenum).GetFrame(); } uint32_t @@ -67,7 +67,8 @@ FrameBlender::GetNumFrames() const int32_t FrameBlender::GetTimeoutForFrame(uint32_t framenum) const { - const int32_t timeout = RawGetFrame(framenum)->GetRawTimeout(); + nsRefPtr frame = RawGetFrame(framenum); + const int32_t timeout = frame->GetRawTimeout(); // Ensure a minimal time between updates so we don't throttle the UI thread. // consider 0 == unspecified and make it fast but not too fast. Unless we have // a single loop GIF. See bug 890743, bug 125137, bug 139677, and bug 207059. @@ -123,23 +124,23 @@ FrameBlender::InsertFrame(uint32_t framenum, imgFrame* aFrame) } } -imgFrame* +already_AddRefed FrameBlender::SwapFrame(uint32_t framenum, imgFrame* aFrame) { NS_ABORT_IF_FALSE(framenum < GetNumFrames(), "Swapping invalid frame!"); - imgFrame* ret; + nsRefPtr ret; // Steal the imgFrame from wherever it's currently stored if (mAnim && mAnim->lastCompositedFrameIndex == int32_t(framenum)) { ret = mAnim->compositingFrame.Forget(); mAnim->lastCompositedFrameIndex = -1; - nsAutoPtr toDelete(mFrames->SwapFrame(framenum, aFrame)); + nsRefPtr toDelete(mFrames->SwapFrame(framenum, aFrame)); } else { ret = mFrames->SwapFrame(framenum, aFrame); } - return ret; + return ret.forget(); } void @@ -307,18 +308,18 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect, // If we just created the composite, it could have anything in its // buffer. Clear whole frame ClearFrame(mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect()); + mAnim->compositingFrame->GetRect()); } else { // Only blank out previous frame area (both color & Mask/Alpha) ClearFrame(mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect(), + mAnim->compositingFrame->GetRect(), prevFrameRect); } break; case FrameBlender::kDisposeClearAll: ClearFrame(mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect()); + mAnim->compositingFrame->GetRect()); break; case FrameBlender::kDisposeRestorePrevious: @@ -326,16 +327,16 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect, // compositingFrame. if (mAnim->compositingPrevFrame) { CopyFrameImage(mAnim->compositingPrevFrame.GetFrameData(), - mAnim->compositingPrevFrame.GetFrame()->GetRect(), + mAnim->compositingPrevFrame->GetRect(), mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect()); + mAnim->compositingFrame->GetRect()); // destroy only if we don't need it for this frame's disposal if (nextFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious) mAnim->compositingPrevFrame.SetFrame(nullptr); } else { ClearFrame(mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect()); + mAnim->compositingFrame->GetRect()); } break; @@ -350,23 +351,23 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect, if (isFullPrevFrame && !prevFrame->GetIsPaletted()) { // Just copy the bits CopyFrameImage(prevFrame.GetFrameData(), - prevFrame.GetFrame()->GetRect(), + prevFrame->GetRect(), mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect()); + mAnim->compositingFrame->GetRect()); } else { if (needToBlankComposite) { // Only blank composite when prev is transparent or not full. if (prevFrame->GetHasAlpha() || !isFullPrevFrame) { ClearFrame(mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect()); + mAnim->compositingFrame->GetRect()); } } DrawFrameTo(prevFrame.GetFrameData(), prevFrameRect, - prevFrame.GetFrame()->PaletteDataLength(), - prevFrame.GetFrame()->GetHasAlpha(), + prevFrame->PaletteDataLength(), + prevFrame->GetHasAlpha(), mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect(), - FrameBlendMethod(prevFrame.GetFrame()->GetBlendMethod())); + mAnim->compositingFrame->GetRect(), + FrameBlendMethod(prevFrame->GetBlendMethod())); } } } @@ -374,7 +375,7 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect, // If we just created the composite, it could have anything in it's // buffers. Clear them ClearFrame(mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect()); + mAnim->compositingFrame->GetRect()); } // Check if the frame we are composing wants the previous image restored afer @@ -398,18 +399,18 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect, } CopyFrameImage(mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect(), + mAnim->compositingFrame->GetRect(), mAnim->compositingPrevFrame.GetFrameData(), - mAnim->compositingPrevFrame.GetFrame()->GetRect()); + mAnim->compositingPrevFrame->GetRect()); } // blit next frame into it's correct spot DrawFrameTo(nextFrame.GetFrameData(), nextFrameRect, - nextFrame.GetFrame()->PaletteDataLength(), - nextFrame.GetFrame()->GetHasAlpha(), + nextFrame->PaletteDataLength(), + nextFrame->GetHasAlpha(), mAnim->compositingFrame.GetFrameData(), - mAnim->compositingFrame.GetFrame()->GetRect(), - FrameBlendMethod(nextFrame.GetFrame()->GetBlendMethod())); + mAnim->compositingFrame->GetRect(), + FrameBlendMethod(nextFrame->GetBlendMethod())); // Set timeout of CompositeFrame to timeout of frame we just composed // Bug 177948 @@ -417,7 +418,8 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect, mAnim->compositingFrame->SetRawTimeout(timeout); // Tell the image that it is fully 'downloaded'. - nsresult rv = mAnim->compositingFrame->ImageUpdated(mAnim->compositingFrame->GetRect()); + nsresult rv = + mAnim->compositingFrame->ImageUpdated(mAnim->compositingFrame->GetRect()); if (NS_FAILED(rv)) { return false; } diff --git a/image/src/FrameBlender.h b/image/src/FrameBlender.h index 3a922ebfab2..85fe191019e 100644 --- a/image/src/FrameBlender.h +++ b/image/src/FrameBlender.h @@ -44,16 +44,16 @@ public: * Get the @aIndex-th frame, including (if applicable) any results of * blending. */ - imgFrame* GetFrame(uint32_t aIndex) const; + already_AddRefed GetFrame(uint32_t aIndex) const; /** * Get the @aIndex-th frame in the frame index, ignoring results of blending. */ - imgFrame* RawGetFrame(uint32_t aIndex) const; + already_AddRefed RawGetFrame(uint32_t aIndex) const; void InsertFrame(uint32_t framenum, imgFrame* aFrame); void RemoveFrame(uint32_t framenum); - imgFrame* SwapFrame(uint32_t framenum, imgFrame* aFrame); + already_AddRefed SwapFrame(uint32_t framenum, imgFrame* aFrame); void ClearFrames(); /* The total number of frames in this image. */ diff --git a/image/src/FrameSequence.cpp b/image/src/FrameSequence.cpp index 544bb51deae..5131f164a1c 100644 --- a/image/src/FrameSequence.cpp +++ b/image/src/FrameSequence.cpp @@ -64,7 +64,7 @@ FrameSequence::InsertFrame(uint32_t framenum, imgFrame* aFrame) } } -imgFrame* +already_AddRefed FrameSequence::SwapFrame(uint32_t framenum, imgFrame* aFrame) { NS_ABORT_IF_FALSE(framenum < mFrames.Length(), "Swapping invalid frame!"); @@ -82,7 +82,7 @@ FrameSequence::SwapFrame(uint32_t framenum, imgFrame* aFrame) mFrames.RemoveElementAt(framenum); } - return ret.Forget(); + return ret.GetFrame(); } size_t @@ -91,9 +91,9 @@ FrameSequence::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocati { size_t n = 0; for (uint32_t i = 0; i < mFrames.Length(); ++i) { - imgFrame* frame = mFrames.SafeElementAt(i, FrameDataPair()); - NS_ABORT_IF_FALSE(frame, "Null frame in frame array!"); - n += frame->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf); + FrameDataPair fdp = mFrames.SafeElementAt(i, FrameDataPair()); + NS_ABORT_IF_FALSE(fdp, "Null frame in frame array!"); + n += fdp->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf); } return n; diff --git a/image/src/FrameSequence.h b/image/src/FrameSequence.h index f281201706d..f011243c7ca 100644 --- a/image/src/FrameSequence.h +++ b/image/src/FrameSequence.h @@ -9,6 +9,7 @@ #include "nsTArray.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/Move.h" #include "gfxTypes.h" #include "imgFrame.h" @@ -32,19 +33,19 @@ public: {} FrameDataPair() - : mFrame(nullptr) + : mFrameData(nullptr) + {} + + FrameDataPair(const FrameDataPair& aOther) + : mFrame(aOther.mFrame) , mFrameData(nullptr) {} - FrameDataPair(FrameDataPair& other) + FrameDataPair(FrameDataPair&& aOther) + : mFrame(Move(aOther.mFrame)) + , mFrameData(aOther.mFrameData) { - mFrame = other.mFrame; - mFrameData = other.mFrameData; - - // since mFrame is an nsAutoPtr, the assignment operator above actually - // nulls out other.mFrame. In order to fully assume ownership over the - // frame, we also null out the other's mFrameData. - other.mFrameData = nullptr; + aOther.mFrameData = nullptr; } ~FrameDataPair() @@ -54,6 +55,24 @@ public: } } + FrameDataPair& operator=(const FrameDataPair& aOther) + { + if (&aOther != this) { + mFrame = aOther.mFrame; + mFrameData = nullptr; + } + return *this; + } + + FrameDataPair& operator=(FrameDataPair&& aOther) + { + MOZ_ASSERT(&aOther != this, "Moving to self"); + mFrame = Move(aOther.mFrame); + mFrameData = aOther.mFrameData; + aOther.mFrameData = nullptr; + return *this; + } + // Lock the frame and store its mFrameData. The frame will be unlocked (and // deleted) when this FrameDataPair is deleted. void LockAndGetData() @@ -71,15 +90,14 @@ public: // Null out this FrameDataPair and return its frame. You must ensure the // frame will be deleted separately. - imgFrame* Forget() + already_AddRefed Forget() { if (mFrameData) { mFrame->UnlockImageData(); } - imgFrame* frame = mFrame.forget(); mFrameData = nullptr; - return frame; + return mFrame.forget(); } bool HasFrameData() const @@ -95,9 +113,10 @@ public: return mFrameData; } - imgFrame* GetFrame() const + already_AddRefed GetFrame() const { - return mFrame; + nsRefPtr frame = mFrame; + return frame.forget(); } // Resets this FrameDataPair to work with a different frame. Takes ownership @@ -112,14 +131,9 @@ public: mFrameData = nullptr; } - operator imgFrame*() const - { - return GetFrame(); - } - imgFrame* operator->() const { - return GetFrame(); + return mFrame.get(); } bool operator==(imgFrame* other) const @@ -127,8 +141,13 @@ public: return mFrame == other; } + operator bool() const + { + return mFrame != nullptr; + } + private: - nsAutoPtr mFrame; + nsRefPtr mFrame; uint8_t* mFrameData; }; @@ -163,7 +182,7 @@ public: * Swap aFrame with the frame at sequence framenum, and return that frame. * You take ownership over the frame returned. */ - imgFrame* SwapFrame(uint32_t framenum, imgFrame* aFrame); + already_AddRefed SwapFrame(uint32_t framenum, imgFrame* aFrame); /** * Remove (and delete) all frames. diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 65b831841f0..0db86106429 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -271,7 +271,7 @@ public: // These values may only be touched on the main thread. WeakPtr weakImage; - nsAutoPtr dstFrame; + nsRefPtr dstFrame; RefPtr srcSurface; RefPtr dstSurface; @@ -390,7 +390,6 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker, ImageResource(aURI), // invoke superclass's constructor mSize(0,0), mFrameDecodeFlags(DECODE_FLAGS_DEFAULT), - mMultipartDecodedFrame(nullptr), mAnim(nullptr), mLockCount(0), mDecodeCount(0), @@ -459,14 +458,13 @@ RasterImage::~RasterImage() // This would be done in ShutdownDecoder, but since mDecoder is non-null, // we didn't call ShutdownDecoder and we need to do it manually. if (GetNumFrames() > 0) { - imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1); + nsRefPtr curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1); curframe->UnlockImageData(); } } delete mAnim; mAnim = nullptr; - delete mMultipartDecodedFrame; // Total statistics num_containers--; @@ -660,7 +658,7 @@ RasterImage::GetType() return imgIContainer::TYPE_RASTER; } -imgFrame* +already_AddRefed RasterImage::GetImgFrameNoDecode(uint32_t framenum) { if (!mAnim) { @@ -670,7 +668,7 @@ RasterImage::GetImgFrameNoDecode(uint32_t framenum) return mFrameBlender.GetFrame(framenum); } -imgFrame* +already_AddRefed RasterImage::GetImgFrame(uint32_t framenum) { nsresult rv = WantDecodedFrames(); @@ -678,10 +676,10 @@ RasterImage::GetImgFrame(uint32_t framenum) return GetImgFrameNoDecode(framenum); } -imgFrame* +already_AddRefed RasterImage::GetDrawableImgFrame(uint32_t framenum) { - imgFrame* frame = nullptr; + nsRefPtr frame; if (mMultipart && framenum == GetCurrentImgFrameIndex()) { // In the multipart case we prefer to use mMultipartDecodedFrame, which is @@ -699,7 +697,7 @@ RasterImage::GetDrawableImgFrame(uint32_t framenum) if (frame && frame->GetCompositingFailed()) return nullptr; - return frame; + return frame.forget(); } uint32_t @@ -711,7 +709,7 @@ RasterImage::GetCurrentImgFrameIndex() const return 0; } -imgFrame* +already_AddRefed RasterImage::GetCurrentImgFrame() { return GetImgFrame(GetCurrentImgFrameIndex()); @@ -731,8 +729,9 @@ RasterImage::FrameIsOpaque(uint32_t aWhichFrame) return false; // See if we can get an image frame. - imgFrame* frame = aWhichFrame == FRAME_FIRST ? GetImgFrameNoDecode(0) - : GetImgFrameNoDecode(GetCurrentImgFrameIndex()); + nsRefPtr frame = aWhichFrame == FRAME_FIRST + ? GetImgFrameNoDecode(0) + : GetImgFrameNoDecode(GetCurrentImgFrameIndex()); // If we don't get a frame, the safe answer is "not opaque". if (!frame) @@ -755,8 +754,9 @@ RasterImage::FrameRect(uint32_t aWhichFrame) } // Get the requested frame. - imgFrame* frame = aWhichFrame == FRAME_FIRST ? GetImgFrameNoDecode(0) - : GetImgFrameNoDecode(GetCurrentImgFrameIndex()); + nsRefPtr frame = aWhichFrame == FRAME_FIRST + ? GetImgFrameNoDecode(0) + : GetImgFrameNoDecode(GetCurrentImgFrameIndex()); // If we have the frame, use that rectangle. if (frame) { @@ -855,7 +855,7 @@ RasterImage::CopyFrame(uint32_t aWhichFrame, // FLAG_SYNC_DECODE uint32_t frameIndex = (aWhichFrame == FRAME_FIRST) ? 0 : GetCurrentImgFrameIndex(); - imgFrame *frame = GetDrawableImgFrame(frameIndex); + nsRefPtr frame = GetDrawableImgFrame(frameIndex); if (!frame) { return nullptr; } @@ -929,7 +929,7 @@ RasterImage::GetFrame(uint32_t aWhichFrame, // FLAG_SYNC_DECODE uint32_t frameIndex = (aWhichFrame == FRAME_FIRST) ? 0 : GetCurrentImgFrameIndex(); - imgFrame *frame = GetDrawableImgFrame(frameIndex); + nsRefPtr frame = GetDrawableImgFrame(frameIndex); if (!frame) { return nullptr; } @@ -1149,7 +1149,7 @@ RasterImage::InternalAddFrameHelper(uint32_t framenum, imgFrame *aFrame, if (framenum > GetNumFrames()) return NS_ERROR_INVALID_ARG; - nsAutoPtr frame(aFrame); + nsRefPtr frame(aFrame); // We are in the middle of decoding. This will be unlocked when we finish // decoding or switch to another frame. @@ -1160,10 +1160,9 @@ RasterImage::InternalAddFrameHelper(uint32_t framenum, imgFrame *aFrame, frame->GetImageData(imageData, imageLength); - *aRetFrame = frame; - - mFrameBlender.InsertFrame(framenum, frame.forget()); + mFrameBlender.InsertFrame(framenum, frame); + frame.forget(aRetFrame); return NS_OK; } @@ -1188,7 +1187,7 @@ RasterImage::InternalAddFrame(uint32_t framenum, if (framenum > GetNumFrames()) return NS_ERROR_INVALID_ARG; - nsAutoPtr frame(new imgFrame()); + nsRefPtr frame(new imgFrame()); nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth); if (!(mSize.width > 0 && mSize.height > 0)) @@ -1200,12 +1199,12 @@ RasterImage::InternalAddFrame(uint32_t framenum, // We know we are in a decoder. Therefore, we must unlock the previous frame // when we move on to decoding into the next frame. if (GetNumFrames() > 0) { - imgFrame *prevframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1); + nsRefPtr prevframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1); prevframe->UnlockImageData(); } if (GetNumFrames() == 0) { - return InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength, + return InternalAddFrameHelper(framenum, frame, imageData, imageLength, paletteData, paletteLength, aRetFrame); } @@ -1216,10 +1215,11 @@ RasterImage::InternalAddFrame(uint32_t framenum, // If we dispose of the first frame by clearing it, then the // First Frame's refresh area is all of itself. // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR) - int32_t frameDisposalMethod = mFrameBlender.RawGetFrame(0)->GetFrameDisposalMethod(); + nsRefPtr firstFrame = mFrameBlender.RawGetFrame(0); + int32_t frameDisposalMethod = firstFrame->GetFrameDisposalMethod(); if (frameDisposalMethod == FrameBlender::kDisposeClear || frameDisposalMethod == FrameBlender::kDisposeRestorePrevious) - mAnim->SetFirstFrameRefreshArea(mFrameBlender.RawGetFrame(0)->GetRect()); + mAnim->SetFirstFrameRefreshArea(firstFrame->GetRect()); } // Calculate firstFrameRefreshArea @@ -1227,7 +1227,7 @@ RasterImage::InternalAddFrame(uint32_t framenum, // We only need to refresh that small area when Frame 0 comes around again mAnim->UnionFirstFrameRefreshArea(frame->GetRect()); - rv = InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength, + rv = InternalAddFrameHelper(framenum, frame, imageData, imageLength, paletteData, paletteLength, aRetFrame); return rv; @@ -1337,7 +1337,7 @@ RasterImage::EnsureFrame(uint32_t aFrameNum, int32_t aX, int32_t aY, paletteData, paletteLength, aRetFrame); } - imgFrame *frame = mFrameBlender.RawGetFrame(aFrameNum); + nsRefPtr frame = mFrameBlender.RawGetFrame(aFrameNum); if (!frame) { return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat, aPaletteDepth, imageData, imageLength, @@ -1354,13 +1354,13 @@ RasterImage::EnsureFrame(uint32_t aFrameNum, int32_t aX, int32_t aY, frame->GetPaletteData(paletteData, paletteLength); } - *aRetFrame = frame; - // We can re-use the frame if it has image data. if (*imageData && paletteData && *paletteData) { + frame.forget(aRetFrame); return NS_OK; } if (*imageData && !paletteData) { + frame.forget(aRetFrame); return NS_OK; } } @@ -1372,12 +1372,11 @@ RasterImage::EnsureFrame(uint32_t aFrameNum, int32_t aX, int32_t aY, frame->UnlockImageData(); mFrameBlender.RemoveFrame(aFrameNum); - nsAutoPtr newFrame(new imgFrame()); + nsRefPtr newFrame(new imgFrame()); nsresult rv = newFrame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth); NS_ENSURE_SUCCESS(rv, rv); - return InternalAddFrameHelper(aFrameNum, newFrame.forget(), imageData, - imageLength, paletteData, paletteLength, - aRetFrame); + return InternalAddFrameHelper(aFrameNum, newFrame, imageData, imageLength, + paletteData, paletteLength, aRetFrame); } nsresult @@ -1404,7 +1403,7 @@ RasterImage::SetFrameAsNonPremult(uint32_t aFrameNum, bool aIsNonPremult) if (aFrameNum >= GetNumFrames()) return NS_ERROR_INVALID_ARG; - imgFrame* frame = mFrameBlender.RawGetFrame(aFrameNum); + nsRefPtr frame = mFrameBlender.RawGetFrame(aFrameNum); NS_ABORT_IF_FALSE(frame, "Calling SetFrameAsNonPremult on frame that doesn't exist!"); NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); @@ -1446,10 +1445,11 @@ RasterImage::DecodingComplete() // CanForciblyDiscard is used instead of CanForciblyDiscardAndRedecode // because we know decoding is complete at this point and this is not // an animation + nsRefPtr firstFrame = mFrameBlender.RawGetFrame(0); if (DiscardingEnabled() && CanForciblyDiscard()) { - mFrameBlender.RawGetFrame(0)->SetDiscardable(); + firstFrame->SetDiscardable(); } - rv = mFrameBlender.RawGetFrame(0)->Optimize(); + rv = firstFrame->Optimize(); NS_ENSURE_SUCCESS(rv, rv); } @@ -1464,7 +1464,6 @@ RasterImage::DecodingComplete() // complexity and it's not really needed since we already are smart about // not displaying the still-decoding frame of an animated image. We may // have already stored an extra frame, though, so we'll release it here. - delete mMultipartDecodedFrame; mMultipartDecodedFrame = nullptr; } } @@ -1497,7 +1496,7 @@ RasterImage::StartAnimation() EnsureAnimExists(); - imgFrame* currentFrame = GetCurrentImgFrame(); + nsRefPtr currentFrame = GetCurrentImgFrame(); // A timeout of -1 means we should display this frame forever. if (currentFrame && mFrameBlender.GetTimeoutForFrame(GetCurrentImgFrameIndex()) < 0) { mAnimationFinished = true; @@ -1964,7 +1963,6 @@ RasterImage::Discard(bool force) mScaleResult.frame = nullptr; // Clear the last decoded multipart frame. - delete mMultipartDecodedFrame; mMultipartDecodedFrame = nullptr; // Flag that we no longer have decoded frames for this image @@ -2089,7 +2087,7 @@ RasterImage::InitDecoder(bool aDoSizeDecode) // case. Regardless, we need to lock the last frame. Our invariant is that, // while we have a decoder open, the last frame is always locked. if (GetNumFrames() > 0) { - imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1); + nsRefPtr curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1); curframe->LockImageData(); } @@ -2171,7 +2169,7 @@ RasterImage::ShutdownDecoder(eShutdownIntent aIntent) // Unlock the last frame (if we have any). Our invariant is that, while we // have a decoder open, the last frame is always locked. if (GetNumFrames() > 0) { - imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1); + nsRefPtr curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1); curframe->UnlockImageData(); } @@ -2563,16 +2561,15 @@ RasterImage::ScalingDone(ScaleRequest* request, ScaleStatus status) if (status == SCALE_DONE) { MOZ_ASSERT(request->done); - imgFrame *scaledFrame = request->dstFrame.forget(); - scaledFrame->ImageUpdated(scaledFrame->GetRect()); + mScaleResult.status = SCALE_DONE; + mScaleResult.frame = request->dstFrame.forget(); + mScaleResult.scaledSize = request->dstSize; + + mScaleResult.frame->ImageUpdated(mScaleResult.frame->GetRect()); if (mStatusTracker) { mStatusTracker->FrameChanged(&request->srcRect); } - - mScaleResult.status = SCALE_DONE; - mScaleResult.frame = scaledFrame; - mScaleResult.scaledSize = request->dstSize; } else { mScaleResult.status = SCALE_INVALID; mScaleResult.frame = nullptr; @@ -2627,7 +2624,7 @@ RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame, GraphicsFilter aFilter, uint32_t aFlags) { - imgFrame *frame = aFrame; + nsRefPtr frame = aFrame; nsIntRect framerect = frame->GetRect(); gfxContextMatrixAutoSaveRestore saveMatrix(aContext); @@ -2764,7 +2761,7 @@ RasterImage::Draw(gfxContext* aContext, uint32_t frameIndex = aWhichFrame == FRAME_FIRST ? 0 : GetCurrentImgFrameIndex(); - imgFrame* frame = GetDrawableImgFrame(frameIndex); + nsRefPtr frame = GetDrawableImgFrame(frameIndex); if (!frame) { return NS_OK; // Getting the frame (above) touches the image and kicks off decoding } @@ -3695,7 +3692,7 @@ RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame, uint32_t frameIndex = aWhichFrame == FRAME_FIRST ? 0 : GetCurrentImgFrameIndex(); - imgFrame* frame = GetDrawableImgFrame(frameIndex); + nsRefPtr frame = GetDrawableImgFrame(frameIndex); if (frame) { RequestScale(frame, destSize); } diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index f7cc5bb95b6..7e3f5b55e5b 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -576,10 +576,10 @@ private: */ void DeleteImgFrame(uint32_t framenum); - imgFrame* GetImgFrameNoDecode(uint32_t framenum); - imgFrame* GetImgFrame(uint32_t framenum); - imgFrame* GetDrawableImgFrame(uint32_t framenum); - imgFrame* GetCurrentImgFrame(); + already_AddRefed GetImgFrameNoDecode(uint32_t framenum); + already_AddRefed GetImgFrame(uint32_t framenum); + already_AddRefed GetDrawableImgFrame(uint32_t framenum); + already_AddRefed GetCurrentImgFrame(); uint32_t GetCurrentImgFrameIndex() const; size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation, @@ -637,9 +637,9 @@ private: // data FrameBlender mFrameBlender; // The last frame we decoded for multipart images. - imgFrame* mMultipartDecodedFrame; + nsRefPtr mMultipartDecodedFrame; - nsCOMPtr mProperties; + nsCOMPtr mProperties; // IMPORTANT: if you use mAnim in a method, call EnsureImageIsDecoded() first to ensure // that the frames actually exist (they may have been discarded to save memory, or @@ -748,7 +748,7 @@ private: // data {} nsIntSize scaledSize; - nsAutoPtr frame; + nsRefPtr frame; ScaleStatus status; }; diff --git a/image/src/imgFrame.cpp b/image/src/imgFrame.cpp index a8a7d2f5e6e..77c89f7776b 100644 --- a/image/src/imgFrame.cpp +++ b/image/src/imgFrame.cpp @@ -438,6 +438,16 @@ nsIntRect imgFrame::GetRect() const return nsIntRect(mOffset, nsIntSize(mSize.width, mSize.height)); } +int32_t +imgFrame::GetStride() const +{ + if (mImageSurface) { + return mImageSurface->Stride(); + } + + return VolatileSurfaceStride(mSize, mFormat); +} + SurfaceFormat imgFrame::GetFormat() const { return mFormat; @@ -665,6 +675,21 @@ imgFrame::GetSurface() return CreateLockedSurface(mVBuf, mSize, mFormat); } +TemporaryRef +imgFrame::GetDrawTarget() +{ + MOZ_ASSERT(mLockCount >= 1, "Should lock before requesting a DrawTarget"); + + uint8_t* data = GetImageData(); + if (!data) { + return nullptr; + } + + int32_t stride = GetStride(); + return gfxPlatform::GetPlatform()-> + CreateDrawTargetForData(data, mSize, stride, mFormat); +} + int32_t imgFrame::GetRawTimeout() const { return mTimeout; diff --git a/image/src/imgFrame.h b/image/src/imgFrame.h index 1af1058f3f9..96eb659d897 100644 --- a/image/src/imgFrame.h +++ b/image/src/imgFrame.h @@ -22,13 +22,16 @@ class imgFrame { typedef gfx::Color Color; typedef gfx::DataSourceSurface DataSourceSurface; + typedef gfx::DrawTarget DrawTarget; typedef gfx::IntSize IntSize; typedef gfx::SourceSurface SourceSurface; typedef gfx::SurfaceFormat SurfaceFormat; public: + MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame) + imgFrame(); - ~imgFrame(); nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, SurfaceFormat aFormat, uint8_t aPaletteDepth = 0); nsresult Optimize(); @@ -40,6 +43,8 @@ public: nsresult ImageUpdated(const nsIntRect &aUpdateRect); nsIntRect GetRect() const; + IntSize GetSize() const { return mSize; } + int32_t GetStride() const; SurfaceFormat GetFormat() const; bool GetNeedsBackground() const; uint32_t GetImageBytesPerRow() const; @@ -72,6 +77,7 @@ public: void SetDiscardable(); TemporaryRef GetSurface(); + TemporaryRef GetDrawTarget(); Color SinglePixelColor() @@ -100,6 +106,8 @@ public: private: // methods + ~imgFrame(); + struct SurfaceWithFormat { nsRefPtr mDrawable; SurfaceFormat mFormat; @@ -180,7 +188,7 @@ private: // data bool Succeeded() { return mSucceeded; } private: - imgFrame* mFrame; + nsRefPtr mFrame; bool mSucceeded; };