Bug 1054076 - Make imgFrame reference counted. r=tn

This commit is contained in:
Seth Fowler 2014-08-22 13:49:54 -07:00
parent 1bf838780b
commit ae00f4faf9
13 changed files with 217 additions and 158 deletions

View File

@ -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<imgFrame> 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();
}
}
}

View File

@ -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<imgFrame> 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);

View File

@ -204,19 +204,21 @@ Decoder::AllocateFrame()
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
imgFrame* frame = nullptr;
nsRefPtr<imgFrame> 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)) {

View File

@ -171,7 +171,11 @@ public:
// status code from that attempt. Clears mNewFrameData.
virtual nsresult AllocateFrame();
imgFrame* GetCurrentFrame() const { return mCurrentFrame; }
already_AddRefed<imgFrame> GetCurrentFrame() const
{
nsRefPtr<imgFrame> frame = mCurrentFrame;
return frame.forget();
}
protected:
@ -230,7 +234,7 @@ protected:
*
*/
RasterImage &mImage;
imgFrame* mCurrentFrame;
nsRefPtr<imgFrame> mCurrentFrame;
RefPtr<imgDecoderObserver> mObserver;
ImageMetadata mImageMetadata;

View File

@ -85,13 +85,12 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime)
int32_t timeout = 0;
RefreshResult ret;
nsRefPtr<imgFrame> 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();

View File

@ -35,27 +35,27 @@ FrameBlender::GetFrameSequence()
return seq.forget();
}
imgFrame*
already_AddRefed<imgFrame>
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<imgFrame>
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<imgFrame> 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<imgFrame>
FrameBlender::SwapFrame(uint32_t framenum, imgFrame* aFrame)
{
NS_ABORT_IF_FALSE(framenum < GetNumFrames(), "Swapping invalid frame!");
imgFrame* ret;
nsRefPtr<imgFrame> 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<imgFrame> toDelete(mFrames->SwapFrame(framenum, aFrame));
nsRefPtr<imgFrame> 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;
}

View File

@ -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<imgFrame> 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<imgFrame> 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<imgFrame> SwapFrame(uint32_t framenum, imgFrame* aFrame);
void ClearFrames();
/* The total number of frames in this image. */

View File

@ -64,7 +64,7 @@ FrameSequence::InsertFrame(uint32_t framenum, imgFrame* aFrame)
}
}
imgFrame*
already_AddRefed<imgFrame>
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;

View File

@ -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<imgFrame> 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<imgFrame> GetFrame() const
{
return mFrame;
nsRefPtr<imgFrame> 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<imgFrame> mFrame;
nsRefPtr<imgFrame> 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<imgFrame> SwapFrame(uint32_t framenum, imgFrame* aFrame);
/**
* Remove (and delete) all frames.

View File

@ -271,7 +271,7 @@ public:
// These values may only be touched on the main thread.
WeakPtr<RasterImage> weakImage;
nsAutoPtr<imgFrame> dstFrame;
nsRefPtr<imgFrame> dstFrame;
RefPtr<SourceSurface> srcSurface;
RefPtr<SourceSurface> 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<imgFrame> 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<imgFrame>
RasterImage::GetImgFrameNoDecode(uint32_t framenum)
{
if (!mAnim) {
@ -670,7 +668,7 @@ RasterImage::GetImgFrameNoDecode(uint32_t framenum)
return mFrameBlender.GetFrame(framenum);
}
imgFrame*
already_AddRefed<imgFrame>
RasterImage::GetImgFrame(uint32_t framenum)
{
nsresult rv = WantDecodedFrames();
@ -678,10 +676,10 @@ RasterImage::GetImgFrame(uint32_t framenum)
return GetImgFrameNoDecode(framenum);
}
imgFrame*
already_AddRefed<imgFrame>
RasterImage::GetDrawableImgFrame(uint32_t framenum)
{
imgFrame* frame = nullptr;
nsRefPtr<imgFrame> 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<imgFrame>
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<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> frame(aFrame);
nsRefPtr<imgFrame> 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<imgFrame> frame(new imgFrame());
nsRefPtr<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> newFrame(new imgFrame());
nsRefPtr<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> 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<imgFrame> frame = GetDrawableImgFrame(frameIndex);
if (frame) {
RequestScale(frame, destSize);
}

View File

@ -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<imgFrame> GetImgFrameNoDecode(uint32_t framenum);
already_AddRefed<imgFrame> GetImgFrame(uint32_t framenum);
already_AddRefed<imgFrame> GetDrawableImgFrame(uint32_t framenum);
already_AddRefed<imgFrame> 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<imgFrame> mMultipartDecodedFrame;
nsCOMPtr<nsIProperties> mProperties;
nsCOMPtr<nsIProperties> 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<imgFrame> frame;
nsRefPtr<imgFrame> frame;
ScaleStatus status;
};

View File

@ -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<DrawTarget>
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;

View File

@ -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<SourceSurface> GetSurface();
TemporaryRef<DrawTarget> GetDrawTarget();
Color
SinglePixelColor()
@ -100,6 +106,8 @@ public:
private: // methods
~imgFrame();
struct SurfaceWithFormat {
nsRefPtr<gfxDrawable> mDrawable;
SurfaceFormat mFormat;
@ -180,7 +188,7 @@ private: // data
bool Succeeded() { return mSucceeded; }
private:
imgFrame* mFrame;
nsRefPtr<imgFrame> mFrame;
bool mSucceeded;
};