Fix crashing if the document loadgroup is cancelled while there are pending tree image loads (bug 324988) r+sr=bzbarsky

git-svn-id: svn://10.0.0.236/branches/MOZILLA_1_8_BRANCH@188513 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bryner%brianryner.com
2006-01-30 23:22:16 +00:00
parent 39e9378a18
commit 6fdff8b285
2 changed files with 49 additions and 55 deletions

View File

@@ -106,18 +106,12 @@
static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
// Enumeration function that cancels all the image requests in our cache
PR_STATIC_CALLBACK(PRBool)
CancelImageRequest(nsHashKey* aKey, void* aData, void* aClosure)
PR_STATIC_CALLBACK(PLDHashOperator)
CancelImageRequest(const nsAString& aKey,
nsTreeImageCacheEntry aEntry, void* aData)
{
nsISupports* supports = NS_STATIC_CAST(nsISupports*, aData);
nsCOMPtr<imgIRequest> request = do_QueryInterface(supports);
nsCOMPtr<imgIDecoderObserver> observer;
request->GetDecoderObserver(getter_AddRefs(observer));
NS_ASSERTION(observer, "No observer? We're leaking!");
request->Cancel(NS_ERROR_FAILURE);
imgIDecoderObserver* observer2 = observer;
NS_RELEASE(observer2); // Balance out the addref from GetImage()
return PR_TRUE;
aEntry.request->Cancel(NS_BINDING_ABORTED);
return PL_DHASH_NEXT;
}
//
@@ -156,7 +150,7 @@ NS_INTERFACE_MAP_END_INHERITING(nsLeafBoxFrame)
// Constructor
nsTreeBodyFrame::nsTreeBodyFrame(nsIPresShell* aPresShell)
:nsLeafBoxFrame(aPresShell), mPresContext(nsnull), mTreeBoxObject(nsnull), mImageCache(nsnull),
:nsLeafBoxFrame(aPresShell), mPresContext(nsnull), mTreeBoxObject(nsnull),
mScrollbar(nsnull), mTopRowIndex(0), mRowHeight(0), mIndentation(0), mStringWidth(-1),
mFocused(PR_FALSE), mHasFixedRowCount(PR_FALSE),
mVerticalOverflow(PR_FALSE), mReflowCallbackPosted(PR_FALSE),
@@ -169,10 +163,7 @@ nsTreeBodyFrame::nsTreeBodyFrame(nsIPresShell* aPresShell)
// Destructor
nsTreeBodyFrame::~nsTreeBodyFrame()
{
if (mImageCache) {
mImageCache->Enumerate(CancelImageRequest);
delete mImageCache;
}
mImageCache.EnumerateRead(CancelImageRequest, nsnull);
delete mSlots;
}
@@ -236,6 +227,7 @@ nsTreeBodyFrame::Init(nsPresContext* aPresContext, nsIContent* aContent,
mIndentation = GetIndentation();
mRowHeight = GetRowHeight();
NS_ENSURE_TRUE(mImageCache.Init(16), NS_ERROR_OUT_OF_MEMORY);
return rv;
}
@@ -1623,29 +1615,27 @@ nsTreeBodyFrame::GetImage(PRInt32 aRowIndex, nsTreeColumn* aCol, PRBool aUseCont
uri->GetSpec(spec);
CopyUTF8toUTF16(spec, imageSrc);
}
nsStringKey key(imageSrc);
if (mImageCache) {
// Look the image up in our cache.
nsCOMPtr<imgIRequest> imgReq = getter_AddRefs(NS_STATIC_CAST(imgIRequest*, mImageCache->Get(&key)));
if (imgReq) {
// Find out if the image has loaded.
PRUint32 status;
imgReq->GetImageStatus(&status);
imgReq->GetImage(aResult); // We hand back the image here. The GetImage call addrefs *aResult.
PRUint32 numFrames = 1;
if (*aResult)
(*aResult)->GetNumFrames(&numFrames);
// Look the image up in our cache.
nsTreeImageCacheEntry entry;
if (mImageCache.Get(imageSrc, &entry)) {
// Find out if the image has loaded.
PRUint32 status;
imgIRequest *imgReq = entry.request;
imgReq->GetImageStatus(&status);
imgReq->GetImage(aResult); // We hand back the image here. The GetImage call addrefs *aResult.
PRUint32 numFrames = 1;
if (*aResult)
(*aResult)->GetNumFrames(&numFrames);
if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || numFrames > 1) {
// We either aren't done loading, or we're animating. Add our row as a listener for invalidations.
nsCOMPtr<imgIDecoderObserver> obs;
imgReq->GetDecoderObserver(getter_AddRefs(obs));
nsCOMPtr<nsITreeImageListener> listener(do_QueryInterface(obs));
if (listener)
listener->AddCell(aRowIndex, aCol);
return NS_OK;
}
if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || numFrames > 1) {
// We either aren't done loading, or we're animating. Add our row as a listener for invalidations.
nsCOMPtr<imgIDecoderObserver> obs;
imgReq->GetDecoderObserver(getter_AddRefs(obs));
nsCOMPtr<nsITreeImageListener> listener(do_QueryInterface(obs));
if (listener)
listener->AddCell(aRowIndex, aCol);
return NS_OK;
}
}
@@ -1696,15 +1686,8 @@ nsTreeBodyFrame::GetImage(PRInt32 aRowIndex, nsTreeColumn* aCol, PRBool aUseCont
// In a case it was already cached.
imageRequest->GetImage(aResult);
if (!mImageCache) {
mImageCache = new nsSupportsHashtable(16);
if (!mImageCache)
return NS_ERROR_OUT_OF_MEMORY;
}
mImageCache->Put(&key, imageRequest);
imgIDecoderObserver* decoderObserverPtr = imgDecoderObserver;
NS_ADDREF(decoderObserverPtr); // Will get released when we remove the cache entry.
nsTreeImageCacheEntry cacheEntry(imageRequest, imgDecoderObserver);
mImageCache.Put(imageSrc, cacheEntry);
}
return NS_OK;
}
@@ -3366,11 +3349,8 @@ NS_IMETHODIMP
nsTreeBodyFrame::ClearStyleAndImageCaches()
{
mStyleCache.Clear();
if (mImageCache) {
mImageCache->Enumerate(CancelImageRequest);
delete mImageCache;
}
mImageCache = nsnull;
mImageCache.EnumerateRead(CancelImageRequest, nsnull);
mImageCache.Clear();
mScrollbar = nsnull;
return NS_OK;
}

View File

@@ -53,6 +53,20 @@
#include "nsTreeColumns.h"
#include "nsTreeImageListener.h"
#include "nsAutoPtr.h"
#include "nsDataHashtable.h"
#include "imgIRequest.h"
#include "imgIDecoderObserver.h"
// An entry in the tree's image cache
struct nsTreeImageCacheEntry
{
nsTreeImageCacheEntry() {}
nsTreeImageCacheEntry(imgIRequest *aRequest, imgIDecoderObserver *aListener)
: request(aRequest), listener(aListener) {}
nsCOMPtr<imgIRequest> request;
nsCOMPtr<imgIDecoderObserver> listener;
};
// The actual frame that paints the cells and rows.
class nsTreeBodyFrame : public nsLeafBoxFrame,
@@ -328,11 +342,11 @@ protected: // Data Members
// (the power set of all row properties).
nsTreeStyleCache mStyleCache;
// A hashtable that maps from URLs to image requests. The URL is provided
// by the view or by the style context. The style context represents
// a resolved :-moz-tree-cell-image (or twisty) pseudo-element.
// A hashtable that maps from URLs to image request/listener pairs. The URL
// is provided by the view or by the style context. The style context
// represents a resolved :-moz-tree-cell-image (or twisty) pseudo-element.
// It maps directly to an imgIRequest.
nsSupportsHashtable* mImageCache;
nsDataHashtable<nsStringHashKey, nsTreeImageCacheEntry> mImageCache;
// Our vertical scrollbar.
nsIFrame* mScrollbar;