Bug 933483 - Don't fire events (and especially request animation frame events) when we're in a modal dialog. r=smaug

This commit is contained in:
Blake Kaplan 2013-12-17 16:12:33 -08:00
parent e9bf501722
commit 8e23aa0ed3
4 changed files with 52 additions and 22 deletions

View File

@ -8565,11 +8565,17 @@ FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments,
return;
for (uint32_t i = 0; i < aDocuments.Length(); ++i) {
// NB: Don't bother trying to fire delayed events on documents that were
// closed before this event ran.
if (!aDocuments[i]->EventHandlingSuppressed()) {
fm->FireDelayedEvents(aDocuments[i]);
nsCOMPtr<nsIPresShell> shell = aDocuments[i]->GetShell();
if (shell) {
shell->FireOrClearDelayedEvents(aFireEvents);
// Only fire events for active documents.
bool fire = aFireEvents &&
aDocuments[i]->GetInnerWindow() &&
aDocuments[i]->GetInnerWindow()->IsCurrentInnerWindow();
shell->FireOrClearDelayedEvents(fire);
}
}
}

View File

@ -992,16 +992,23 @@ nsFocusManager::FireDelayedEvents(nsIDocument* aDocument)
NS_ENSURE_ARG(aDocument);
// fire any delayed focus and blur events in the same order that they were added
for (uint32_t i = 0; i < mDelayedBlurFocusEvents.Length(); i++)
{
if (mDelayedBlurFocusEvents[i].mDocument == aDocument &&
!aDocument->EventHandlingSuppressed()) {
uint32_t type = mDelayedBlurFocusEvents[i].mType;
nsCOMPtr<EventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
nsCOMPtr<nsIPresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
mDelayedBlurFocusEvents.RemoveElementAt(i);
SendFocusOrBlurEvent(type, presShell, aDocument, target, 0, false);
--i;
for (uint32_t i = 0; i < mDelayedBlurFocusEvents.Length(); i++) {
if (mDelayedBlurFocusEvents[i].mDocument == aDocument) {
if (!aDocument->GetInnerWindow() ||
!aDocument->GetInnerWindow()->IsCurrentInnerWindow()) {
// If the document was navigated away from or is defunct, don't bother
// firing events on it. Note the symmetry between this condition and
// the similar one in nsDocument.cpp:FireOrClearDelayedEvents.
mDelayedBlurFocusEvents.RemoveElementAt(i);
--i;
} else if (!aDocument->EventHandlingSuppressed()) {
uint32_t type = mDelayedBlurFocusEvents[i].mType;
nsCOMPtr<EventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
nsCOMPtr<nsIPresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
mDelayedBlurFocusEvents.RemoveElementAt(i);
SendFocusOrBlurEvent(type, presShell, aDocument, target, 0, false);
--i;
}
}
}

View File

@ -1266,6 +1266,8 @@ nsGlobalWindow::~nsGlobalWindow()
while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
PR_REMOVE_AND_INIT_LINK(w);
}
DropOuterWindowDocs();
} else {
Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
mMutationBits ? 1 : 0);
@ -1286,9 +1288,9 @@ nsGlobalWindow::~nsGlobalWindow()
if (outer) {
outer->MaybeClearInnerWindow(this);
}
}
ClearDelayedEventsAndDropDocument();
MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed());
}
// Outer windows are always supposed to call CleanUp before letting themselves
// be destroyed. And while CleanUp generally seems to be intended to clean up
@ -1360,12 +1362,11 @@ nsGlobalWindow::MaybeForgiveSpamCount()
}
void
nsGlobalWindow::ClearDelayedEventsAndDropDocument()
nsGlobalWindow::DropOuterWindowDocs()
{
if (mDoc && mDoc->EventHandlingSuppressed()) {
mDoc->UnsuppressEventHandlingAndFireEvents(false);
}
MOZ_ASSERT(IsOuterWindow());
mDoc = nullptr;
mSuspendedDoc = nullptr;
}
void
@ -1545,6 +1546,10 @@ nsGlobalWindow::FreeInnerObjects()
mDocumentPrincipal = mDoc->NodePrincipal();
mDocumentURI = mDoc->GetDocumentURI();
mDocBaseURI = mDoc->GetDocBaseURI();
if (mDoc->EventHandlingSuppressed()) {
mDoc->UnsuppressEventHandlingAndFireEvents(false);
}
}
// Remove our reference to the document and the document principal.
@ -2271,6 +2276,10 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// document.
mDoc = aDocument;
// Take this opportunity to clear mSuspendedDoc. Our old inner window is now
// responsible for unsuspending it.
mSuspendedDoc = nullptr;
#ifdef DEBUG
mLastOpenedURI = aDocument->GetDocumentURI();
#endif
@ -2766,7 +2775,7 @@ nsGlobalWindow::DetachFromDocShell()
mDocBaseURI = mDoc->GetDocBaseURI();
// Release our document reference
ClearDelayedEventsAndDropDocument();
DropOuterWindowDocs();
mFocusedNode = nullptr;
}
@ -8170,6 +8179,8 @@ nsGlobalWindow::ReallyCloseWindow()
void
nsGlobalWindow::EnterModalState()
{
FORWARD_TO_OUTER_VOID(EnterModalState, ());
// GetScriptableTop, not GetTop, so that EnterModalState works properly with
// <iframe mozbrowser>.
nsGlobalWindow* topWin = GetScriptableTop();
@ -8203,10 +8214,8 @@ nsGlobalWindow::EnterModalState()
NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
mSuspendedDoc = topWin->GetExtantDoc();
if (mSuspendedDoc && mSuspendedDoc->EventHandlingSuppressed()) {
if (mSuspendedDoc) {
mSuspendedDoc->SuppressEventHandling();
} else {
mSuspendedDoc = nullptr;
}
}
topWin->mModalStateDepth++;
@ -8285,6 +8294,8 @@ private:
void
nsGlobalWindow::LeaveModalState()
{
FORWARD_TO_OUTER_VOID(LeaveModalState, ());
nsGlobalWindow* topWin = GetScriptableTop();
if (!topWin) {

View File

@ -981,7 +981,7 @@ protected:
// Object Management
virtual ~nsGlobalWindow();
void ClearDelayedEventsAndDropDocument();
void DropOuterWindowDocs();
void CleanUp();
void ClearControllers();
nsresult FinalClose();
@ -1476,6 +1476,12 @@ protected:
nsAutoPtr<nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*> > mCachedXBLPrototypeHandlers;
// mSuspendedDoc is only set on outer windows. It's useful when we get matched
// EnterModalState/LeaveModalState calls, in which case the outer window is
// responsible for unsuspending events on the document. If we don't (for
// example, if the outer window is closed before the LeaveModalState call),
// then the inner window whose mDoc is our mSuspendedDoc is responsible for
// unsuspending it.
nsCOMPtr<nsIDocument> mSuspendedDoc;
nsRefPtr<mozilla::dom::indexedDB::IDBFactory> mIndexedDB;