Bug 731868. Make reference from CanvasRenderingContext2DUserData to its 2D (non-Azure) context weak. r=jrmuizel

--HG--
extra : rebase_source : 364040f753bec622ed8df03773bf76053d17963a
This commit is contained in:
Robert O'Callahan 2012-06-01 18:26:36 +12:00
parent b6d824fdff
commit 7fdb3ae809

View File

@ -297,6 +297,7 @@ NS_INTERFACE_MAP_BEGIN(nsTextMetrics)
NS_INTERFACE_MAP_END
struct nsCanvasBidiProcessor;
class CanvasRenderingContext2DUserData;
/**
** nsCanvasRenderingContext2D
@ -377,6 +378,7 @@ public:
nsRefPtr<gfxPath> mPath;
};
friend class PathAutoSaveRestore;
friend class CanvasRenderingContext2DUserData;
protected:
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
@ -439,6 +441,8 @@ protected:
// the canvas element we're a context of
nsCOMPtr<nsIDOMHTMLCanvasElement> mCanvasElement;
nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
nsHTMLCanvasElement *HTMLCanvasElement() {
return static_cast<nsHTMLCanvasElement*>(mCanvasElement.get());
}
@ -755,6 +759,40 @@ protected:
friend struct nsCanvasBidiProcessor;
};
class CanvasRenderingContext2DUserData : public LayerUserData {
public:
CanvasRenderingContext2DUserData(nsCanvasRenderingContext2D *aContext)
: mContext(aContext)
{
aContext->mUserDatas.AppendElement(this);
}
~CanvasRenderingContext2DUserData()
{
if (mContext) {
mContext->mUserDatas.RemoveElement(this);
}
}
static void DidTransactionCallback(void* aData)
{
CanvasRenderingContext2DUserData* self =
static_cast<CanvasRenderingContext2DUserData*>(aData);
if (self->mContext) {
self->mContext->MarkContextClean();
}
}
bool IsForContext(nsCanvasRenderingContext2D *aContext)
{
return mContext == aContext;
}
void Forget()
{
mContext = nsnull;
}
private:
nsCanvasRenderingContext2D *mContext;
};
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCanvasRenderingContext2D)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCanvasRenderingContext2D)
@ -810,6 +848,10 @@ nsCanvasRenderingContext2D::nsCanvasRenderingContext2D()
nsCanvasRenderingContext2D::~nsCanvasRenderingContext2D()
{
Reset();
// Drop references from all CanvasRenderingContext2DUserDatas to this context
for (PRUint32 i = 0; i < mUserDatas.Length(); ++i) {
mUserDatas[i]->Forget();
}
sNumLivingContexts--;
if (!sNumLivingContexts) {
delete[] sUnpremultiplyTable;
@ -4160,19 +4202,6 @@ nsCanvasRenderingContext2D::SetMozImageSmoothingEnabled(bool val)
static PRUint8 g2DContextLayerUserData;
class CanvasRenderingContext2DUserData : public LayerUserData {
public:
CanvasRenderingContext2DUserData(nsHTMLCanvasElement *aContent)
: mContent(aContent) {}
static void DidTransactionCallback(void* aData)
{
static_cast<CanvasRenderingContext2DUserData*>(aData)->mContent->MarkContextClean();
}
private:
nsRefPtr<nsHTMLCanvasElement> mContent;
};
already_AddRefed<CanvasLayer>
nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
CanvasLayer *aOldLayer,
@ -4181,10 +4210,14 @@ nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
if (!EnsureSurface())
return nsnull;
if (!mResetLayer && aOldLayer &&
aOldLayer->HasUserData(&g2DContextLayerUserData)) {
NS_ADDREF(aOldLayer);
return aOldLayer;
if (!mResetLayer && aOldLayer) {
CanvasRenderingContext2DUserData* userData =
static_cast<CanvasRenderingContext2DUserData*>(
aOldLayer->GetUserData(&g2DContextLayerUserData));
if (userData && userData->IsForContext(this)) {
NS_ADDREF(aOldLayer);
return aOldLayer;
}
}
nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
@ -4206,7 +4239,7 @@ nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
// releasing the reference to the element.
// The userData will receive DidTransactionCallbacks, which flush the
// the invalidation state to indicate that the canvas is up to date.
userData = new CanvasRenderingContext2DUserData(HTMLCanvasElement());
userData = new CanvasRenderingContext2DUserData(this);
canvasLayer->SetDidTransactionCallback(
CanvasRenderingContext2DUserData::DidTransactionCallback, userData);
}