Loading image/AnimationFrameBuffer.cpp +30 −24 Original line number Diff line number Diff line Loading @@ -432,26 +432,31 @@ RawAccessFrameRef AnimationFrameRecyclingQueue::RecycleFrame( RawAccessFrameRef recycledFrame; if (mRecycle.front().mFrame) { recycledFrame = mRecycle.front().mFrame->RawAccessRef(); MOZ_ASSERT(recycledFrame); recycledFrame = mRecycle.front().mFrame->RawAccessRef( gfx::DataSourceSurface::READ_WRITE); mRecycle.pop_front(); // If we couldn't map in the surface, it is probably because the frame was // finalized and we did not expect to need to write into it again. This // happens for the first frames produced during an animation. if (recycledFrame) { if (mForceUseFirstFrameRefreshArea) { // We are still crossing the loop boundary and cannot rely upon the dirty // rects of entries in mDisplay to be representative. E.g. The first frame // is probably has a full frame dirty rect. // We are still crossing the loop boundary and cannot rely upon the // dirty rects of entries in mDisplay to be representative. E.g. The // first frame is probably has a full frame dirty rect. aRecycleRect = mFirstFrameRefreshArea; } else { // Calculate the recycle rect for the recycled frame. This is the // cumulative dirty rect of all of the frames ahead of us to be displayed, // and to be used for recycling. Or in other words, the dirty rect between // the recycled frame and the decoded frame which reuses the buffer. // cumulative dirty rect of all of the frames ahead of us to be // displayed, and to be used for recycling. Or in other words, the dirty // rect between the recycled frame and the decoded frame which reuses // the buffer. // // We know at this point that mRecycle contains either frames from the end // of the animation with the first frame refresh area as the dirty rect // (plus the first frame likewise) and frames with their actual dirty rect // from the start. mDisplay should also only contain frames from the start // of the animation onwards. // We know at this point that mRecycle contains either frames from the // end of the animation with the first frame refresh area as the dirty // rect (plus the first frame likewise) and frames with their actual // dirty rect from the start. mDisplay should also only contain frames // from the start of the animation onwards. aRecycleRect.SetRect(0, 0, 0, 0); for (const RefPtr<imgFrame>& frame : mDisplay) { aRecycleRect = aRecycleRect.Union(frame->GetDirtyRect()); Loading @@ -460,6 +465,7 @@ RawAccessFrameRef AnimationFrameRecyclingQueue::RecycleFrame( aRecycleRect = aRecycleRect.Union(entry.mDirtyRect); } } } } else { mRecycle.pop_front(); } Loading image/Decoder.cpp +9 −5 Original line number Diff line number Diff line Loading @@ -303,8 +303,7 @@ nsresult Decoder::AllocateFrame(const gfx::IntSize& aOutputSize, if (mCurrentFrame) { mHasFrameToTake = true; // Gather the raw pointers the decoders will use. mCurrentFrame->GetImageData(&mImageData, &mImageDataLength); mImageData = mCurrentFrame.Data(); // We should now be on |aFrameNum|. (Note that we're comparing the frame // number, which is zero-based, with the frame count, which is one-based.) Loading @@ -316,6 +315,9 @@ nsresult Decoder::AllocateFrame(const gfx::IntSize& aOutputSize, // Update our state to reflect the new frame. MOZ_ASSERT(!mInFrame, "Starting new frame but not done with old one!"); mInFrame = true; } else { mImageData = nullptr; mImageDataLength = 0; } return mCurrentFrame ? NS_OK : NS_ERROR_FAILURE; Loading Loading @@ -376,7 +378,8 @@ RawAccessFrameRef Decoder::AllocateFrameInternal( // animation parameters elsewhere. For now we just drop it. bool blocked = ref.get() == mRestoreFrame.get(); if (!blocked) { blocked = NS_FAILED(ref->InitForDecoderRecycle(aAnimParams.ref())); blocked = NS_FAILED( ref->InitForDecoderRecycle(aAnimParams.ref(), &mImageDataLength)); } if (blocked) { Loading @@ -395,12 +398,13 @@ RawAccessFrameRef Decoder::AllocateFrameInternal( bool nonPremult = bool(mSurfaceFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA); auto frame = MakeNotNull<RefPtr<imgFrame>>(); if (NS_FAILED(frame->InitForDecoder(aOutputSize, aFormat, nonPremult, aAnimParams, bool(mFrameRecycler)))) { aAnimParams, bool(mFrameRecycler), &mImageDataLength))) { NS_WARNING("imgFrame::Init should succeed"); return RawAccessFrameRef(); } ref = frame->RawAccessRef(); ref = frame->RawAccessRef(gfx::DataSourceSurface::READ_WRITE); if (!ref) { frame->Abort(); return RawAccessFrameRef(); Loading image/imgFrame.cpp +16 −33 Original line number Diff line number Diff line Loading @@ -145,7 +145,8 @@ imgFrame::~imgFrame() { nsresult imgFrame::InitForDecoder(const nsIntSize& aImageSize, SurfaceFormat aFormat, bool aNonPremult, const Maybe<AnimationParams>& aAnimParams, bool aShouldRecycle) { bool aShouldRecycle, uint32_t* aImageDataLength) { // Assert for properties that should be verified by decoders, // warn for properties related to bad content. if (!SurfaceCache::IsLegalSize(aImageSize)) { Loading Loading @@ -217,10 +218,15 @@ nsresult imgFrame::InitForDecoder(const nsIntSize& aImageSize, } } if (aImageDataLength) { *aImageDataLength = GetImageDataLength(); } return NS_OK; } nsresult imgFrame::InitForDecoderRecycle(const AnimationParams& aAnimParams) { nsresult imgFrame::InitForDecoderRecycle(const AnimationParams& aAnimParams, uint32_t* aImageDataLength) { // We want to recycle this frame, but there is no guarantee that consumers are // done with it in a timely manner. Let's ensure they are done with it first. MonitorAutoLock lock(mMonitor); Loading Loading @@ -287,6 +293,10 @@ nsresult imgFrame::InitForDecoderRecycle(const AnimationParams& aAnimParams) { mDisposalMethod = aAnimParams.mDisposalMethod; mDirtyRect = GetRect(); if (aImageDataLength) { *aImageDataLength = GetImageDataLength(); } return NS_OK; } Loading Loading @@ -391,7 +401,10 @@ nsresult imgFrame::InitWithDrawable(gfxDrawable* aDrawable, DrawableFrameRef imgFrame::DrawableRef() { return DrawableFrameRef(this); } RawAccessFrameRef imgFrame::RawAccessRef() { return RawAccessFrameRef(this); } RawAccessFrameRef imgFrame::RawAccessRef( gfx::DataSourceSurface::MapType aMapType) { return RawAccessFrameRef(this, aMapType); } imgFrame::SurfaceWithFormat imgFrame::SurfaceForDrawing( bool aDoPartialDecode, bool aDoTile, ImageRegion& aRegion, Loading Loading @@ -586,36 +599,6 @@ uint32_t imgFrame::GetImageDataLength() const { return GetImageBytesPerRow() * mImageSize.height; } void imgFrame::GetImageData(uint8_t** aData, uint32_t* aLength) const { MonitorAutoLock lock(mMonitor); GetImageDataInternal(aData, aLength); } void imgFrame::GetImageDataInternal(uint8_t** aData, uint32_t* aLength) const { mMonitor.AssertCurrentThreadOwns(); MOZ_ASSERT(mRawSurface); if (mRawSurface) { // TODO: This is okay for now because we only realloc shared surfaces on // the main thread after decoding has finished, but if animations want to // read frame data off the main thread, we will need to reconsider this. *aData = mRawSurface->GetData(); MOZ_ASSERT(*aData, "mRawSurface is non-null, but GetData is null in GetImageData"); } else { *aData = nullptr; } *aLength = GetImageDataLength(); } uint8_t* imgFrame::GetImageData() const { uint8_t* data; uint32_t length; GetImageData(&data, &length); return data; } void imgFrame::FinalizeSurface() { MonitorAutoLock lock(mMonitor); FinalizeSurfaceInternal(); Loading image/imgFrame.h +32 −12 Original line number Diff line number Diff line Loading @@ -55,7 +55,8 @@ class imgFrame { nsresult InitForDecoder(const nsIntSize& aImageSize, SurfaceFormat aFormat, bool aNonPremult, const Maybe<AnimationParams>& aAnimParams, bool aShouldRecycle); bool aShouldRecycle, uint32_t* aImageDataLength = nullptr); /** * Reinitialize this imgFrame with the new parameters, but otherwise retain Loading @@ -65,7 +66,8 @@ class imgFrame { * given an IDecoderFrameRecycler object which may yield a recycled imgFrame * that was discarded to save memory. */ nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams); nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams, uint32_t* aImageDataLength = nullptr); /** * Initialize this imgFrame with a new surface and draw the provided Loading @@ -90,7 +92,8 @@ class imgFrame { /** * Create a RawAccessFrameRef for the frame. */ RawAccessFrameRef RawAccessRef(); RawAccessFrameRef RawAccessRef( gfx::DataSourceSurface::MapType aMapType = gfx::DataSourceSurface::READ); bool Draw(gfxContext* aContext, const ImageRegion& aRegion, SamplingFilter aSamplingFilter, uint32_t aImageFlags, Loading Loading @@ -160,8 +163,6 @@ class imgFrame { BlendMethod GetBlendMethod() const { return mBlendMethod; } DisposalMethod GetDisposalMethod() const { return mDisposalMethod; } bool FormatHasAlpha() const { return mFormat == SurfaceFormat::OS_RGBA; } void GetImageData(uint8_t** aData, uint32_t* length) const; uint8_t* GetImageData() const; const IntRect& GetDirtyRect() const { return mDirtyRect; } void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; } Loading @@ -187,7 +188,6 @@ class imgFrame { bool AreAllPixelsWritten() const MOZ_REQUIRES(mMonitor); nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect); void GetImageDataInternal(uint8_t** aData, uint32_t* length) const; uint32_t GetImageBytesPerRow() const; uint32_t GetImageDataLength() const; void FinalizeSurfaceInternal(); Loading Loading @@ -357,13 +357,25 @@ class DrawableFrameRef final { */ class RawAccessFrameRef final { public: RawAccessFrameRef() : mData(nullptr) {} RawAccessFrameRef() = default; explicit RawAccessFrameRef(imgFrame* aFrame) : mFrame(aFrame), mData(nullptr) { explicit RawAccessFrameRef(imgFrame* aFrame, gfx::DataSourceSurface::MapType aMapType) : mFrame(aFrame) { MOZ_ASSERT(mFrame, "Need a frame"); mData = mFrame->GetImageData(); // Note that we do not use ScopedMap here because it holds a strong // reference to the underlying surface. This affects the reuse logic for // recycling in imgFrame::InitForDecoderRecycle. { MonitorAutoLock lock(mFrame->mMonitor); gfx::DataSourceSurface::MappedSurface map; if (mFrame->mRawSurface && mFrame->mRawSurface->Map(aMapType, &map)) { MOZ_ASSERT(map.mData); mData = map.mData; } } if (!mData) { mFrame = nullptr; } Loading @@ -374,11 +386,15 @@ class RawAccessFrameRef final { aOther.mData = nullptr; } ~RawAccessFrameRef() {} ~RawAccessFrameRef() { reset(); } RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) { MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); if (mFrame) { MonitorAutoLock lock(mFrame->mMonitor); mFrame->mRawSurface->Unmap(); } mFrame = std::move(aOther.mFrame); mData = aOther.mData; aOther.mData = nullptr; Loading @@ -402,6 +418,10 @@ class RawAccessFrameRef final { const imgFrame* get() const { return mFrame; } void reset() { if (mFrame) { MonitorAutoLock lock(mFrame->mMonitor); mFrame->mRawSurface->Unmap(); } mFrame = nullptr; mData = nullptr; } Loading @@ -413,7 +433,7 @@ class RawAccessFrameRef final { RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete; RefPtr<imgFrame> mFrame; uint8_t* mData; uint8_t* mData = nullptr; }; } // namespace image Loading image/test/gtest/TestAnimationFrameBuffer.cpp +3 −6 Original line number Diff line number Diff line Loading @@ -759,8 +759,7 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingResetBeforeComplete) { while (!buffer.Recycle().empty()) { gfx::IntRect recycleRect; RawAccessFrameRef frameRef = buffer.RecycleFrame(recycleRect); EXPECT_TRUE(frameRef); EXPECT_FALSE(ReinitForRecycle(frameRef)); EXPECT_FALSE(frameRef); } // Reinsert the first two frames as recyclable and reset again. Loading Loading @@ -829,8 +828,7 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingRect) { gfx::IntRect recycleRect; EXPECT_FALSE(buffer.Recycle().empty()); RawAccessFrameRef frameRef = buffer.RecycleFrame(recycleRect); EXPECT_TRUE(frameRef); EXPECT_FALSE(ReinitForRecycle(frameRef)); EXPECT_FALSE(frameRef); EXPECT_TRUE(buffer.Recycle().empty()); // Insert a recyclable partial frame. Its dirty rect shouldn't matter since Loading @@ -842,8 +840,7 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingRect) { VerifyAdvance(buffer, 5, true); EXPECT_FALSE(buffer.Recycle().empty()); frameRef = buffer.RecycleFrame(recycleRect); EXPECT_TRUE(frameRef); EXPECT_FALSE(ReinitForRecycle(frameRef)); EXPECT_FALSE(frameRef); EXPECT_TRUE(buffer.Recycle().empty()); // Insert a recyclable partial frame. Its dirty rect should match the recycle Loading Loading
image/AnimationFrameBuffer.cpp +30 −24 Original line number Diff line number Diff line Loading @@ -432,26 +432,31 @@ RawAccessFrameRef AnimationFrameRecyclingQueue::RecycleFrame( RawAccessFrameRef recycledFrame; if (mRecycle.front().mFrame) { recycledFrame = mRecycle.front().mFrame->RawAccessRef(); MOZ_ASSERT(recycledFrame); recycledFrame = mRecycle.front().mFrame->RawAccessRef( gfx::DataSourceSurface::READ_WRITE); mRecycle.pop_front(); // If we couldn't map in the surface, it is probably because the frame was // finalized and we did not expect to need to write into it again. This // happens for the first frames produced during an animation. if (recycledFrame) { if (mForceUseFirstFrameRefreshArea) { // We are still crossing the loop boundary and cannot rely upon the dirty // rects of entries in mDisplay to be representative. E.g. The first frame // is probably has a full frame dirty rect. // We are still crossing the loop boundary and cannot rely upon the // dirty rects of entries in mDisplay to be representative. E.g. The // first frame is probably has a full frame dirty rect. aRecycleRect = mFirstFrameRefreshArea; } else { // Calculate the recycle rect for the recycled frame. This is the // cumulative dirty rect of all of the frames ahead of us to be displayed, // and to be used for recycling. Or in other words, the dirty rect between // the recycled frame and the decoded frame which reuses the buffer. // cumulative dirty rect of all of the frames ahead of us to be // displayed, and to be used for recycling. Or in other words, the dirty // rect between the recycled frame and the decoded frame which reuses // the buffer. // // We know at this point that mRecycle contains either frames from the end // of the animation with the first frame refresh area as the dirty rect // (plus the first frame likewise) and frames with their actual dirty rect // from the start. mDisplay should also only contain frames from the start // of the animation onwards. // We know at this point that mRecycle contains either frames from the // end of the animation with the first frame refresh area as the dirty // rect (plus the first frame likewise) and frames with their actual // dirty rect from the start. mDisplay should also only contain frames // from the start of the animation onwards. aRecycleRect.SetRect(0, 0, 0, 0); for (const RefPtr<imgFrame>& frame : mDisplay) { aRecycleRect = aRecycleRect.Union(frame->GetDirtyRect()); Loading @@ -460,6 +465,7 @@ RawAccessFrameRef AnimationFrameRecyclingQueue::RecycleFrame( aRecycleRect = aRecycleRect.Union(entry.mDirtyRect); } } } } else { mRecycle.pop_front(); } Loading
image/Decoder.cpp +9 −5 Original line number Diff line number Diff line Loading @@ -303,8 +303,7 @@ nsresult Decoder::AllocateFrame(const gfx::IntSize& aOutputSize, if (mCurrentFrame) { mHasFrameToTake = true; // Gather the raw pointers the decoders will use. mCurrentFrame->GetImageData(&mImageData, &mImageDataLength); mImageData = mCurrentFrame.Data(); // We should now be on |aFrameNum|. (Note that we're comparing the frame // number, which is zero-based, with the frame count, which is one-based.) Loading @@ -316,6 +315,9 @@ nsresult Decoder::AllocateFrame(const gfx::IntSize& aOutputSize, // Update our state to reflect the new frame. MOZ_ASSERT(!mInFrame, "Starting new frame but not done with old one!"); mInFrame = true; } else { mImageData = nullptr; mImageDataLength = 0; } return mCurrentFrame ? NS_OK : NS_ERROR_FAILURE; Loading Loading @@ -376,7 +378,8 @@ RawAccessFrameRef Decoder::AllocateFrameInternal( // animation parameters elsewhere. For now we just drop it. bool blocked = ref.get() == mRestoreFrame.get(); if (!blocked) { blocked = NS_FAILED(ref->InitForDecoderRecycle(aAnimParams.ref())); blocked = NS_FAILED( ref->InitForDecoderRecycle(aAnimParams.ref(), &mImageDataLength)); } if (blocked) { Loading @@ -395,12 +398,13 @@ RawAccessFrameRef Decoder::AllocateFrameInternal( bool nonPremult = bool(mSurfaceFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA); auto frame = MakeNotNull<RefPtr<imgFrame>>(); if (NS_FAILED(frame->InitForDecoder(aOutputSize, aFormat, nonPremult, aAnimParams, bool(mFrameRecycler)))) { aAnimParams, bool(mFrameRecycler), &mImageDataLength))) { NS_WARNING("imgFrame::Init should succeed"); return RawAccessFrameRef(); } ref = frame->RawAccessRef(); ref = frame->RawAccessRef(gfx::DataSourceSurface::READ_WRITE); if (!ref) { frame->Abort(); return RawAccessFrameRef(); Loading
image/imgFrame.cpp +16 −33 Original line number Diff line number Diff line Loading @@ -145,7 +145,8 @@ imgFrame::~imgFrame() { nsresult imgFrame::InitForDecoder(const nsIntSize& aImageSize, SurfaceFormat aFormat, bool aNonPremult, const Maybe<AnimationParams>& aAnimParams, bool aShouldRecycle) { bool aShouldRecycle, uint32_t* aImageDataLength) { // Assert for properties that should be verified by decoders, // warn for properties related to bad content. if (!SurfaceCache::IsLegalSize(aImageSize)) { Loading Loading @@ -217,10 +218,15 @@ nsresult imgFrame::InitForDecoder(const nsIntSize& aImageSize, } } if (aImageDataLength) { *aImageDataLength = GetImageDataLength(); } return NS_OK; } nsresult imgFrame::InitForDecoderRecycle(const AnimationParams& aAnimParams) { nsresult imgFrame::InitForDecoderRecycle(const AnimationParams& aAnimParams, uint32_t* aImageDataLength) { // We want to recycle this frame, but there is no guarantee that consumers are // done with it in a timely manner. Let's ensure they are done with it first. MonitorAutoLock lock(mMonitor); Loading Loading @@ -287,6 +293,10 @@ nsresult imgFrame::InitForDecoderRecycle(const AnimationParams& aAnimParams) { mDisposalMethod = aAnimParams.mDisposalMethod; mDirtyRect = GetRect(); if (aImageDataLength) { *aImageDataLength = GetImageDataLength(); } return NS_OK; } Loading Loading @@ -391,7 +401,10 @@ nsresult imgFrame::InitWithDrawable(gfxDrawable* aDrawable, DrawableFrameRef imgFrame::DrawableRef() { return DrawableFrameRef(this); } RawAccessFrameRef imgFrame::RawAccessRef() { return RawAccessFrameRef(this); } RawAccessFrameRef imgFrame::RawAccessRef( gfx::DataSourceSurface::MapType aMapType) { return RawAccessFrameRef(this, aMapType); } imgFrame::SurfaceWithFormat imgFrame::SurfaceForDrawing( bool aDoPartialDecode, bool aDoTile, ImageRegion& aRegion, Loading Loading @@ -586,36 +599,6 @@ uint32_t imgFrame::GetImageDataLength() const { return GetImageBytesPerRow() * mImageSize.height; } void imgFrame::GetImageData(uint8_t** aData, uint32_t* aLength) const { MonitorAutoLock lock(mMonitor); GetImageDataInternal(aData, aLength); } void imgFrame::GetImageDataInternal(uint8_t** aData, uint32_t* aLength) const { mMonitor.AssertCurrentThreadOwns(); MOZ_ASSERT(mRawSurface); if (mRawSurface) { // TODO: This is okay for now because we only realloc shared surfaces on // the main thread after decoding has finished, but if animations want to // read frame data off the main thread, we will need to reconsider this. *aData = mRawSurface->GetData(); MOZ_ASSERT(*aData, "mRawSurface is non-null, but GetData is null in GetImageData"); } else { *aData = nullptr; } *aLength = GetImageDataLength(); } uint8_t* imgFrame::GetImageData() const { uint8_t* data; uint32_t length; GetImageData(&data, &length); return data; } void imgFrame::FinalizeSurface() { MonitorAutoLock lock(mMonitor); FinalizeSurfaceInternal(); Loading
image/imgFrame.h +32 −12 Original line number Diff line number Diff line Loading @@ -55,7 +55,8 @@ class imgFrame { nsresult InitForDecoder(const nsIntSize& aImageSize, SurfaceFormat aFormat, bool aNonPremult, const Maybe<AnimationParams>& aAnimParams, bool aShouldRecycle); bool aShouldRecycle, uint32_t* aImageDataLength = nullptr); /** * Reinitialize this imgFrame with the new parameters, but otherwise retain Loading @@ -65,7 +66,8 @@ class imgFrame { * given an IDecoderFrameRecycler object which may yield a recycled imgFrame * that was discarded to save memory. */ nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams); nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams, uint32_t* aImageDataLength = nullptr); /** * Initialize this imgFrame with a new surface and draw the provided Loading @@ -90,7 +92,8 @@ class imgFrame { /** * Create a RawAccessFrameRef for the frame. */ RawAccessFrameRef RawAccessRef(); RawAccessFrameRef RawAccessRef( gfx::DataSourceSurface::MapType aMapType = gfx::DataSourceSurface::READ); bool Draw(gfxContext* aContext, const ImageRegion& aRegion, SamplingFilter aSamplingFilter, uint32_t aImageFlags, Loading Loading @@ -160,8 +163,6 @@ class imgFrame { BlendMethod GetBlendMethod() const { return mBlendMethod; } DisposalMethod GetDisposalMethod() const { return mDisposalMethod; } bool FormatHasAlpha() const { return mFormat == SurfaceFormat::OS_RGBA; } void GetImageData(uint8_t** aData, uint32_t* length) const; uint8_t* GetImageData() const; const IntRect& GetDirtyRect() const { return mDirtyRect; } void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; } Loading @@ -187,7 +188,6 @@ class imgFrame { bool AreAllPixelsWritten() const MOZ_REQUIRES(mMonitor); nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect); void GetImageDataInternal(uint8_t** aData, uint32_t* length) const; uint32_t GetImageBytesPerRow() const; uint32_t GetImageDataLength() const; void FinalizeSurfaceInternal(); Loading Loading @@ -357,13 +357,25 @@ class DrawableFrameRef final { */ class RawAccessFrameRef final { public: RawAccessFrameRef() : mData(nullptr) {} RawAccessFrameRef() = default; explicit RawAccessFrameRef(imgFrame* aFrame) : mFrame(aFrame), mData(nullptr) { explicit RawAccessFrameRef(imgFrame* aFrame, gfx::DataSourceSurface::MapType aMapType) : mFrame(aFrame) { MOZ_ASSERT(mFrame, "Need a frame"); mData = mFrame->GetImageData(); // Note that we do not use ScopedMap here because it holds a strong // reference to the underlying surface. This affects the reuse logic for // recycling in imgFrame::InitForDecoderRecycle. { MonitorAutoLock lock(mFrame->mMonitor); gfx::DataSourceSurface::MappedSurface map; if (mFrame->mRawSurface && mFrame->mRawSurface->Map(aMapType, &map)) { MOZ_ASSERT(map.mData); mData = map.mData; } } if (!mData) { mFrame = nullptr; } Loading @@ -374,11 +386,15 @@ class RawAccessFrameRef final { aOther.mData = nullptr; } ~RawAccessFrameRef() {} ~RawAccessFrameRef() { reset(); } RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) { MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); if (mFrame) { MonitorAutoLock lock(mFrame->mMonitor); mFrame->mRawSurface->Unmap(); } mFrame = std::move(aOther.mFrame); mData = aOther.mData; aOther.mData = nullptr; Loading @@ -402,6 +418,10 @@ class RawAccessFrameRef final { const imgFrame* get() const { return mFrame; } void reset() { if (mFrame) { MonitorAutoLock lock(mFrame->mMonitor); mFrame->mRawSurface->Unmap(); } mFrame = nullptr; mData = nullptr; } Loading @@ -413,7 +433,7 @@ class RawAccessFrameRef final { RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete; RefPtr<imgFrame> mFrame; uint8_t* mData; uint8_t* mData = nullptr; }; } // namespace image Loading
image/test/gtest/TestAnimationFrameBuffer.cpp +3 −6 Original line number Diff line number Diff line Loading @@ -759,8 +759,7 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingResetBeforeComplete) { while (!buffer.Recycle().empty()) { gfx::IntRect recycleRect; RawAccessFrameRef frameRef = buffer.RecycleFrame(recycleRect); EXPECT_TRUE(frameRef); EXPECT_FALSE(ReinitForRecycle(frameRef)); EXPECT_FALSE(frameRef); } // Reinsert the first two frames as recyclable and reset again. Loading Loading @@ -829,8 +828,7 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingRect) { gfx::IntRect recycleRect; EXPECT_FALSE(buffer.Recycle().empty()); RawAccessFrameRef frameRef = buffer.RecycleFrame(recycleRect); EXPECT_TRUE(frameRef); EXPECT_FALSE(ReinitForRecycle(frameRef)); EXPECT_FALSE(frameRef); EXPECT_TRUE(buffer.Recycle().empty()); // Insert a recyclable partial frame. Its dirty rect shouldn't matter since Loading @@ -842,8 +840,7 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingRect) { VerifyAdvance(buffer, 5, true); EXPECT_FALSE(buffer.Recycle().empty()); frameRef = buffer.RecycleFrame(recycleRect); EXPECT_TRUE(frameRef); EXPECT_FALSE(ReinitForRecycle(frameRef)); EXPECT_FALSE(frameRef); EXPECT_TRUE(buffer.Recycle().empty()); // Insert a recyclable partial frame. Its dirty rect should match the recycle Loading