Bug 1057894 (Part 2) - Add RAII smart handles for imgFrame locking. r=tn

This commit is contained in:
Seth Fowler 2014-09-10 17:06:45 -07:00
parent 3fa8c4b046
commit 53036348cb
2 changed files with 172 additions and 20 deletions

View File

@ -312,6 +312,18 @@ nsresult imgFrame::Optimize()
return NS_OK;
}
DrawableFrameRef
imgFrame::DrawableRef()
{
return DrawableFrameRef(this);
}
RawAccessFrameRef
imgFrame::RawAccessRef()
{
return RawAccessFrameRef(this);
}
imgFrame::SurfaceWithFormat
imgFrame::SurfaceForDrawing(bool aDoPadding,
bool aDoPartialDecode,

View File

@ -8,6 +8,7 @@
#define imgFrame_h
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "mozilla/Mutex.h"
#include "mozilla/VolatileBuffer.h"
#include "gfxDrawable.h"
@ -17,6 +18,8 @@ namespace mozilla {
namespace image {
class ImageRegion;
class DrawableFrameRef;
class RawAccessFrameRef;
class imgFrame
{
@ -36,6 +39,9 @@ public:
nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, SurfaceFormat aFormat, uint8_t aPaletteDepth = 0);
nsresult Optimize();
DrawableFrameRef DrawableRef();
RawAccessFrameRef RawAccessRef();
bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
const nsIntMargin& aPadding, GraphicsFilter aFilter,
uint32_t aImageFlags);
@ -165,31 +171,165 @@ private: // data
/** Have we called DiscardTracker::InformAllocation()? */
bool mInformedDiscardTracker;
friend class DrawableFrameRef;
friend class RawAccessFrameRef;
};
// An RAII class to ensure it's easy to balance locks and unlocks on
// imgFrames.
class AutoFrameLocker
/**
* A reference to an imgFrame that holds the imgFrame's surface in memory,
* allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
* true, then calls to Draw() and GetSurface() are guaranteed to succeed.
*/
class DrawableFrameRef MOZ_FINAL
{
// Implementation details for safe boolean conversion.
typedef void (DrawableFrameRef::* ConvertibleToBool)(float*****, double*****);
void nonNull(float*****, double*****) {}
public:
explicit AutoFrameLocker(imgFrame* frame)
: mFrame(frame)
, mSucceeded(NS_SUCCEEDED(frame->LockImageData()))
DrawableFrameRef() { }
explicit DrawableFrameRef(imgFrame* aFrame)
: mFrame(aFrame)
, mRef(aFrame->mVBuf)
{
if (mRef.WasBufferPurged()) {
mFrame = nullptr;
mRef = nullptr;
}
}
DrawableFrameRef(DrawableFrameRef&& aOther)
: mFrame(aOther.mFrame.forget())
, mRef(Move(aOther.mRef))
{ }
~AutoFrameLocker()
DrawableFrameRef& operator=(DrawableFrameRef&& aOther)
{
if (mSucceeded) {
MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
mFrame = aOther.mFrame.forget();
mRef = Move(aOther.mRef);
return *this;
}
operator ConvertibleToBool() const
{
return bool(mFrame) ? &DrawableFrameRef::nonNull : 0;
}
imgFrame* operator->()
{
MOZ_ASSERT(mFrame);
return mFrame;
}
const imgFrame* operator->() const
{
MOZ_ASSERT(mFrame);
return mFrame;
}
imgFrame* get() { return mFrame; }
const imgFrame* get() const { return mFrame; }
void reset()
{
mFrame = nullptr;
mRef = nullptr;
}
private:
nsRefPtr<imgFrame> mFrame;
VolatileBufferPtr<uint8_t> mRef;
};
/**
* A reference to an imgFrame that holds the imgFrame's surface in memory in a
* format appropriate for access as raw data. If you have a RawAccessFrameRef
* |ref| and |if (ref)| is true, then calls to GetImageData(), GetPaletteData(),
* and GetDrawTarget() are guaranteed to succeed. This guarantee is stronger
* than DrawableFrameRef, so everything that a valid DrawableFrameRef guarantees
* is also guaranteed by a valid RawAccessFrameRef.
*
* This may be considerably more expensive than is necessary just for drawing,
* so only use this when you need to read or write the raw underlying image data
* that the imgFrame holds.
*/
class RawAccessFrameRef MOZ_FINAL
{
// Implementation details for safe boolean conversion.
typedef void (RawAccessFrameRef::* ConvertibleToBool)(float*****, double*****);
void nonNull(float*****, double*****) {}
public:
RawAccessFrameRef() { }
explicit RawAccessFrameRef(imgFrame* aFrame)
: mFrame(aFrame)
{
MOZ_ASSERT(mFrame, "Need a frame");
if (NS_FAILED(mFrame->LockImageData())) {
mFrame->UnlockImageData();
mFrame = nullptr;
}
}
RawAccessFrameRef(RawAccessFrameRef&& aOther)
: mFrame(aOther.mFrame.forget())
{ }
~RawAccessFrameRef()
{
if (mFrame) {
mFrame->UnlockImageData();
}
}
// Whether the lock request succeeded.
bool Succeeded() { return mSucceeded; }
RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther)
{
MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
if (mFrame) {
mFrame->UnlockImageData();
}
mFrame = aOther.mFrame.forget();
return *this;
}
operator ConvertibleToBool() const
{
return bool(mFrame) ? &RawAccessFrameRef::nonNull : 0;
}
imgFrame* operator->()
{
MOZ_ASSERT(mFrame);
return mFrame.get();
}
const imgFrame* operator->() const
{
MOZ_ASSERT(mFrame);
return mFrame;
}
imgFrame* get() { return mFrame; }
const imgFrame* get() const { return mFrame; }
void reset()
{
if (mFrame) {
mFrame->UnlockImageData();
}
mFrame = nullptr;
}
private:
nsRefPtr<imgFrame> mFrame;
bool mSucceeded;
};
} // namespace image