mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 717872 - Store a frame's raw image data pointer beside its imgFrame pointer so we can access it without having to lock the frame. r=seth
This patch makes us store imgFrames in FrameBlender with a new sort-of-tuple, FrameDataPair, that is smart enough to be able to lock and unlock imgFrames, and can be transparently cast to an imgFrame, but doesn't do too much else. The alternative, storing a separate array of uint8_t pointers, seemed too complicated.
This commit is contained in:
parent
97e991daf1
commit
7406a5c6fb
@ -7,9 +7,7 @@
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "RasterImage.h"
|
||||
#include "imgFrame.h"
|
||||
|
||||
#define PIXMAN_DONT_DEFINE_STDINT
|
||||
#include "pixman.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -34,11 +32,11 @@ 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.SafeElementAt(0, nullptr);
|
||||
return mFrames.SafeElementAt(0, FrameDataPair());
|
||||
}
|
||||
if (mAnim->lastCompositedFrameIndex == int32_t(framenum))
|
||||
return mAnim->compositingFrame;
|
||||
return mFrames.SafeElementAt(framenum, nullptr);
|
||||
return mFrames.SafeElementAt(framenum, FrameDataPair());
|
||||
}
|
||||
|
||||
imgFrame*
|
||||
@ -46,10 +44,10 @@ 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.SafeElementAt(0, nullptr);
|
||||
return mFrames.SafeElementAt(0, FrameDataPair());
|
||||
}
|
||||
|
||||
return mFrames.SafeElementAt(framenum, nullptr);
|
||||
return mFrames.SafeElementAt(framenum, FrameDataPair());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@ -63,17 +61,14 @@ FrameBlender::RemoveFrame(uint32_t framenum)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(framenum < mFrames.Length(), "Deleting invalid frame!");
|
||||
|
||||
delete mFrames[framenum];
|
||||
mFrames[framenum] = nullptr;
|
||||
mFrames.RemoveElementAt(framenum);
|
||||
}
|
||||
|
||||
void
|
||||
FrameBlender::ClearFrames()
|
||||
{
|
||||
for (uint32_t i = 0; i < mFrames.Length(); ++i) {
|
||||
delete mFrames[i];
|
||||
}
|
||||
// Since FrameDataPair holds an nsAutoPtr to its frame, clearing the mFrames
|
||||
// array also deletes all the frames.
|
||||
mFrames.Clear();
|
||||
}
|
||||
|
||||
@ -84,6 +79,10 @@ FrameBlender::InsertFrame(uint32_t framenum, imgFrame* aFrame)
|
||||
mFrames.InsertElementAt(framenum, aFrame);
|
||||
if (GetNumFrames() > 1) {
|
||||
EnsureAnimExists();
|
||||
|
||||
// Whenever we have more than one frame, we always lock *all* our frames
|
||||
// so we have all the image data pointers.
|
||||
mFrames[framenum].LockAndGetData();
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,13 +90,40 @@ imgFrame*
|
||||
FrameBlender::SwapFrame(uint32_t framenum, imgFrame* aFrame)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(framenum < mFrames.Length(), "Swapping invalid frame!");
|
||||
imgFrame* ret = mFrames.SafeElementAt(framenum, nullptr);
|
||||
mFrames.RemoveElementAt(framenum);
|
||||
if (aFrame) {
|
||||
mFrames.InsertElementAt(framenum, aFrame);
|
||||
|
||||
FrameDataPair ret;
|
||||
|
||||
// Steal the imgFrame from wherever it's currently stored
|
||||
if (mAnim && mAnim->lastCompositedFrameIndex == int32_t(framenum)) {
|
||||
ret = mAnim->compositingFrame;
|
||||
mAnim->lastCompositedFrameIndex = -1;
|
||||
} else if (framenum < mFrames.Length()) {
|
||||
ret = mFrames[framenum];
|
||||
}
|
||||
|
||||
return ret;
|
||||
mFrames.RemoveElementAt(framenum);
|
||||
if (aFrame) {
|
||||
InsertFrame(framenum, aFrame);
|
||||
}
|
||||
|
||||
return ret.Forget();
|
||||
}
|
||||
|
||||
void
|
||||
FrameBlender::EnsureAnimExists()
|
||||
{
|
||||
if (!mAnim) {
|
||||
// Create the animation context
|
||||
mAnim = new Anim();
|
||||
|
||||
// We should only get into this code path directly after we've created our
|
||||
// second frame (hence we know we're animated).
|
||||
MOZ_ASSERT(mFrames.Length() == 2);
|
||||
|
||||
// Whenever we have more than one frame, we always lock *all* our frames
|
||||
// so we have all the image data pointers.
|
||||
mFrames[0].LockAndGetData();
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
@ -112,9 +138,9 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect,
|
||||
return false;
|
||||
}
|
||||
|
||||
imgFrame* prevFrame = mFrames[aPrevFrameIndex];
|
||||
imgFrame* nextFrame = mFrames[aNextFrameIndex];
|
||||
if (!prevFrame || !nextFrame) {
|
||||
FrameDataPair& prevFrame = mFrames[aPrevFrameIndex];
|
||||
FrameDataPair& nextFrame = mFrames[aNextFrameIndex];
|
||||
if (!prevFrame.HasFrameData() || !nextFrame.HasFrameData()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -201,13 +227,14 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect,
|
||||
|
||||
// Create the Compositing Frame
|
||||
if (!mAnim->compositingFrame) {
|
||||
mAnim->compositingFrame = new imgFrame();
|
||||
mAnim->compositingFrame.SetFrame(new imgFrame());
|
||||
nsresult rv = mAnim->compositingFrame->Init(0, 0, mSize.width, mSize.height,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
if (NS_FAILED(rv)) {
|
||||
mAnim->compositingFrame = nullptr;
|
||||
mAnim->compositingFrame.SetFrame(nullptr);
|
||||
return false;
|
||||
}
|
||||
mAnim->compositingFrame.LockAndGetData();
|
||||
needToBlankComposite = true;
|
||||
} else if (int32_t(aNextFrameIndex) != mAnim->lastCompositedFrameIndex+1) {
|
||||
|
||||
@ -269,7 +296,7 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect,
|
||||
|
||||
// destroy only if we don't need it for this frame's disposal
|
||||
if (nextFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious)
|
||||
mAnim->compositingPrevFrame = nullptr;
|
||||
mAnim->compositingPrevFrame.SetFrame(nullptr);
|
||||
} else {
|
||||
ClearFrame(mAnim->compositingFrame);
|
||||
}
|
||||
@ -312,13 +339,15 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect,
|
||||
// It would be better if we just stored the area that nextFrame is going to
|
||||
// overwrite.
|
||||
if (!mAnim->compositingPrevFrame) {
|
||||
mAnim->compositingPrevFrame = new imgFrame();
|
||||
mAnim->compositingPrevFrame.SetFrame(new imgFrame());
|
||||
nsresult rv = mAnim->compositingPrevFrame->Init(0, 0, mSize.width, mSize.height,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
if (NS_FAILED(rv)) {
|
||||
mAnim->compositingPrevFrame = nullptr;
|
||||
mAnim->compositingPrevFrame.SetFrame(nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
mAnim->compositingPrevFrame.LockAndGetData();
|
||||
}
|
||||
|
||||
CopyFrameImage(mAnim->compositingFrame, mAnim->compositingPrevFrame);
|
||||
@ -352,7 +381,7 @@ FrameBlender::DoBlend(nsIntRect* aDirtyRect,
|
||||
// frame next time around
|
||||
if (CopyFrameImage(mAnim->compositingFrame, nextFrame)) {
|
||||
prevFrame->SetFrameDisposalMethod(FrameBlender::kDisposeClearAll);
|
||||
mAnim->compositingFrame = nullptr;
|
||||
mAnim->compositingFrame.SetFrame(nullptr);
|
||||
mAnim->lastCompositedFrameIndex = -1;
|
||||
return true;
|
||||
}
|
||||
@ -567,9 +596,7 @@ FrameBlender::Discard()
|
||||
NS_ABORT_IF_FALSE(!mAnim, "Asked to discard for animated image!");
|
||||
|
||||
// Delete all the decoded frames, then clear the array.
|
||||
for (uint32_t i = 0; i < mFrames.Length(); ++i)
|
||||
delete mFrames[i];
|
||||
mFrames.Clear();
|
||||
ClearFrames();
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -578,7 +605,7 @@ FrameBlender::SizeOfDecodedWithComputedFallbackIfHeap(gfxASurface::MemoryLocatio
|
||||
{
|
||||
size_t n = 0;
|
||||
for (uint32_t i = 0; i < mFrames.Length(); ++i) {
|
||||
imgFrame* frame = mFrames.SafeElementAt(i, nullptr);
|
||||
imgFrame* frame = mFrames.SafeElementAt(i, FrameDataPair());
|
||||
NS_ABORT_IF_FALSE(frame, "Null frame in frame array!");
|
||||
n += frame->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
|
||||
}
|
||||
|
@ -11,19 +11,134 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "gfxASurface.h"
|
||||
|
||||
class imgFrame;
|
||||
#include "imgFrame.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
/**
|
||||
* FrameDataPair is a slightly-smart tuple of (frame, raw frame data) where the
|
||||
* raw frame data is allowed to be (and is, initially) null.
|
||||
*
|
||||
* If you call LockAndGetData, you will be able to call GetFrameData() on that
|
||||
* instance, and when the FrameDataPair is destructed, the imgFrame lock will
|
||||
* be unlocked.
|
||||
*/
|
||||
class FrameDataPair
|
||||
{
|
||||
public:
|
||||
explicit FrameDataPair(imgFrame* frame)
|
||||
: mFrame(frame)
|
||||
, mFrameData(nullptr)
|
||||
{}
|
||||
|
||||
FrameDataPair()
|
||||
: mFrame(nullptr)
|
||||
, mFrameData(nullptr)
|
||||
{}
|
||||
|
||||
FrameDataPair(FrameDataPair& other)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
~FrameDataPair()
|
||||
{
|
||||
if (mFrameData) {
|
||||
mFrame->UnlockImageData();
|
||||
}
|
||||
}
|
||||
|
||||
// Lock the frame and store its mFrameData. The frame will be unlocked (and
|
||||
// deleted) when this FrameDataPair is deleted.
|
||||
void LockAndGetData()
|
||||
{
|
||||
if (mFrame) {
|
||||
if (NS_SUCCEEDED(mFrame->LockImageData())) {
|
||||
if (mFrame->GetIsPaletted()) {
|
||||
mFrameData = reinterpret_cast<uint8_t*>(mFrame->GetPaletteData());
|
||||
} else {
|
||||
mFrameData = mFrame->GetImageData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Null out this FrameDataPair and return its frame. You must ensure the
|
||||
// frame will be deleted separately.
|
||||
imgFrame* Forget()
|
||||
{
|
||||
if (mFrameData) {
|
||||
mFrame->UnlockImageData();
|
||||
}
|
||||
|
||||
imgFrame* frame = mFrame.forget();
|
||||
mFrameData = nullptr;
|
||||
return frame;
|
||||
}
|
||||
|
||||
bool HasFrameData() const
|
||||
{
|
||||
if (mFrameData) {
|
||||
MOZ_ASSERT(!!mFrame);
|
||||
}
|
||||
return !!mFrameData;
|
||||
}
|
||||
|
||||
uint8_t* GetFrameData() const
|
||||
{
|
||||
return mFrameData;
|
||||
}
|
||||
|
||||
imgFrame* GetFrame() const
|
||||
{
|
||||
return mFrame;
|
||||
}
|
||||
|
||||
// Resets this FrameDataPair to work with a different frame. Takes ownership
|
||||
// of the frame, deleting the old frame (if any).
|
||||
void SetFrame(imgFrame* frame)
|
||||
{
|
||||
if (mFrameData) {
|
||||
mFrame->UnlockImageData();
|
||||
}
|
||||
|
||||
mFrame = frame;
|
||||
mFrameData = nullptr;
|
||||
}
|
||||
|
||||
operator imgFrame*() const
|
||||
{
|
||||
return GetFrame();
|
||||
}
|
||||
|
||||
imgFrame* operator->() const
|
||||
{
|
||||
return GetFrame();
|
||||
}
|
||||
|
||||
bool operator==(imgFrame* other) const
|
||||
{
|
||||
return mFrame == other;
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoPtr<imgFrame> mFrame;
|
||||
uint8_t* mFrameData;
|
||||
};
|
||||
|
||||
/**
|
||||
* FrameBlender stores and gives access to imgFrames. It also knows how to
|
||||
* blend frames from previous to next, looping if necessary.
|
||||
*
|
||||
* All logic about when and whether to blend are external to FrameBlender.
|
||||
*/
|
||||
|
||||
class FrameBlender
|
||||
{
|
||||
public:
|
||||
@ -95,7 +210,7 @@ private:
|
||||
struct Anim
|
||||
{
|
||||
//! Track the last composited frame for Optimizations (See DoComposite code)
|
||||
int32_t lastCompositedFrameIndex;
|
||||
int32_t lastCompositedFrameIndex;
|
||||
|
||||
/** For managing blending of frames
|
||||
*
|
||||
@ -105,7 +220,7 @@ private:
|
||||
* lastCompositedFrameIndex to -1. Code assume that if
|
||||
* lastCompositedFrameIndex >= 0 then compositingFrame exists.
|
||||
*/
|
||||
nsAutoPtr<imgFrame> compositingFrame;
|
||||
FrameDataPair compositingFrame;
|
||||
|
||||
/** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
|
||||
*
|
||||
@ -113,20 +228,14 @@ private:
|
||||
* stored in cases where the image specifies it wants the last frame back
|
||||
* when it's done with the current frame.
|
||||
*/
|
||||
nsAutoPtr<imgFrame> compositingPrevFrame;
|
||||
FrameDataPair compositingPrevFrame;
|
||||
|
||||
Anim() :
|
||||
lastCompositedFrameIndex(-1)
|
||||
{}
|
||||
};
|
||||
|
||||
inline void EnsureAnimExists()
|
||||
{
|
||||
if (!mAnim) {
|
||||
// Create the animation context
|
||||
mAnim = new Anim();
|
||||
}
|
||||
}
|
||||
void EnsureAnimExists();
|
||||
|
||||
/** Clears an area of <aFrame> with transparent black.
|
||||
*
|
||||
@ -170,16 +279,8 @@ private:
|
||||
|
||||
private: // data
|
||||
//! All the frames of the image
|
||||
// IMPORTANT: if you use mFrames in a method, call EnsureImageIsDecoded() first
|
||||
// to ensure that the frames actually exist (they may have been discarded to save
|
||||
// memory, or we may be decoding on draw).
|
||||
nsTArray<imgFrame*> mFrames;
|
||||
|
||||
nsTArray<FrameDataPair> mFrames;
|
||||
nsIntSize mSize;
|
||||
|
||||
// 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
|
||||
// we maybe decoding on draw).
|
||||
Anim* mAnim;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user