Make sure to always remove the dummy layout request on presshell destruction

and not to post events after we have revoked them.  Bug 284354, r+sr=roc


git-svn-id: svn://10.0.0.236/trunk@170120 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bzbarsky%mit.edu 2005-03-03 04:46:03 +00:00
parent 7c2b893117
commit 5fc500de3f

View File

@ -1335,7 +1335,7 @@ protected:
void DoneRemovingReflowCommands();
nsresult AddDummyLayoutRequest(void);
nsresult RemoveDummyLayoutRequest(nsIRequest* aDummyLayoutRequest);
nsresult RemoveDummyLayoutRequest();
void WillCauseReflow() { ++mChangeNestCount; }
nsresult DidCauseReflow();
@ -1415,7 +1415,10 @@ protected:
nsCOMPtr<nsICaret> mCaret;
PRInt16 mSelectionFlags;
PRPackedBool mBatchReflows; // When set to true, the pres shell batches reflow commands.
PRPackedBool mBatchReflows; // When set to true, the pres shell batches reflow commands.
// When mDummyLayoutRequestEventPosted is true, we have an event
// posted that will call RemoveDummyLayoutRequest when it fires.
PRPackedBool mDummyLayoutRequestEventPosted;
PresShellViewEventListener *mViewEventListener;
nsCOMPtr<nsIEventQueueService> mEventQueueService;
nsCOMPtr<nsIEventQueue> mReflowEventQueue;
@ -1423,6 +1426,23 @@ protected:
StackArena* mStackArena;
nsCOMPtr<nsIDragService> mDragService;
PRInt32 mRCCreatedDuringLoad; // Counter to keep track of reflow commands created during doc
// The dummy layout request is used to prevent onload from firing
// until after all the reflows that were posted during document load
// have been processed. The control flow here is the following:
// 1) Any time a reflow command is added while the document is loading, if
// we do not already have a dummy layout request we go ahead and create
// one.
// 2) Any time we've removed all reflow commands that were added during
// document load and have a mDummyLayoutRequest we post an event to
// remove this request. The one exception is when we're destroying the
// presshell; then we don't post an event (see item #4).
// 3) While the event to remove the request is posted,
// mDummyLayoutRequestEventPosted is set to true. It's set to false when
// the event fires, before removing the request. While this boolean is
// set, additional events are _not_ posted.
// 4) Destroy() guarantees that the dummy layout request is removed by
// calling RemoveDummyLayoutRequest(), since we may already have no
// reflow commands around and we revoke our events.
nsCOMPtr<nsIRequest> mDummyLayoutRequest;
// used for list of posted events and attribute changes. To be done
@ -1933,7 +1953,7 @@ PresShell::Destroy()
NS_RELEASE(mViewEventListener);
}
// Revoke pending reflow events
// Revoke pending events
mReflowEventQueue = nsnull;
nsCOMPtr<nsIEventQueue> eventQueue;
mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
@ -1942,6 +1962,8 @@ PresShell::Destroy()
CancelAllReflowCommands();
RemoveDummyLayoutRequest();
KillResizeEventTimer();
// Now that mReflowCommandTable won't be accessed anymore, finish it
@ -6509,11 +6531,9 @@ struct DummyLayoutRequestEvent : public PLEvent {
void HandleEvent() {
// Hold a ref here, just in case, since we can trigger DOM event dispatch
nsRefPtr<PresShell> presShell = NS_STATIC_CAST(PresShell*, owner);
presShell->RemoveDummyLayoutRequest(mDummyLayoutRequest);
mDummyLayoutRequest = nsnull;
presShell->mDummyLayoutRequestEventPosted = PR_FALSE;
presShell->RemoveDummyLayoutRequest();
}
nsCOMPtr<nsIRequest> mDummyLayoutRequest;
};
PR_STATIC_CALLBACK(void*)
@ -6541,34 +6561,38 @@ DummyLayoutRequestEvent::DummyLayoutRequestEvent(PresShell* aPresShell)
PL_InitEvent(this, aPresShell, ::HandleDummyLayoutRequestPLEvent,
::DestroyDummyLayoutRequestPLEvent);
// Steal the presshell's mDummyLayoutRequest so that we don't post this event
// multiple times.
aPresShell->mDummyLayoutRequest.swap(mDummyLayoutRequest);
}
void
PresShell::DoneRemovingReflowCommands()
{
if (mRCCreatedDuringLoad == 0 && mDummyLayoutRequest && !mIsReflowing) {
if (mRCCreatedDuringLoad == 0 && mDummyLayoutRequest && !mIsReflowing &&
!mIsDestroying && !mDummyLayoutRequestEventPosted) {
// Post an event to remove mDummyLayoutRequest from the loadgroup
nsCOMPtr<nsIEventQueue> eventQueue;
mEventQueueService->
GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
getter_AddRefs(eventQueue));
if (!eventQueue) {
NS_WARNING("onload won't fire, due to failure to get event queue.");
return;
}
DummyLayoutRequestEvent* evt = new DummyLayoutRequestEvent(this);
if (!evt) {
NS_WARNING("onload won't fire, due to failure to create event.");
return;
}
nsresult rv = eventQueue->PostEvent(evt);
if (NS_FAILED(rv)) {
NS_WARNING("onload won't fire, due to failure to post dummy layout "
"request event");
PL_DestroyEvent(evt);
return;
}
mDummyLayoutRequestEventPosted = PR_TRUE;
}
}
@ -6599,7 +6623,7 @@ PresShell::AddDummyLayoutRequest(void)
}
nsresult
PresShell::RemoveDummyLayoutRequest(nsIRequest* aRequest)
PresShell::RemoveDummyLayoutRequest()
{
nsresult rv = NS_OK;
@ -6608,12 +6632,15 @@ PresShell::RemoveDummyLayoutRequest(nsIRequest* aRequest)
if (mDocument)
loadGroup = mDocument->GetDocumentLoadGroup();
if (loadGroup && aRequest) {
rv = loadGroup->RemoveRequest(aRequest, nsnull, NS_OK);
if (loadGroup && mDummyLayoutRequest) {
rv = loadGroup->RemoveRequest(mDummyLayoutRequest, nsnull, NS_OK);
NS_ENSURE_SUCCESS(rv, rv);
PR_LOG(gLog, PR_LOG_ALWAYS,
("presshell=%p, Removed dummy layout request %p", this, aRequest));
("presshell=%p, Removed dummy layout request %p", this,
mDummyLayoutRequest.get()));
mDummyLayoutRequest = nsnull;
}
}
return rv;