Bug 1268320 - stop event tree processing if the document goes shutdown, r=yzen

This commit is contained in:
Alexander Surkov 2016-05-19 14:35:20 -04:00
parent b067cf32c4
commit db7566fedf
4 changed files with 81 additions and 8 deletions

View File

@ -181,12 +181,15 @@ TreeMutation::Done()
// EventTree
void
EventTree::Process()
EventTree::Process(const RefPtr<DocAccessible>& aDeathGrip)
{
while (mFirst) {
// Skip a node and its subtree if its container is not in the document.
if (mFirst->mContainer->IsInDocument()) {
mFirst->Process();
mFirst->Process(aDeathGrip);
if (aDeathGrip->IsDefunct()) {
return;
}
}
mFirst = mFirst->mNext.forget();
}
@ -195,6 +198,7 @@ EventTree::Process()
"No container, no events");
MOZ_ASSERT(!mContainer || !mContainer->IsDefunct(),
"Processing events for defunct container");
MOZ_ASSERT(!mFireReorder || mContainer, "No target for reorder event");
// Fire mutation events.
uint32_t eventsCount = mDependentEvents.Length();
@ -202,10 +206,18 @@ EventTree::Process()
AccMutationEvent* mtEvent = mDependentEvents[jdx];
MOZ_ASSERT(mtEvent->mEventRule != AccEvent::eDoNotEmit,
"The event shouldn't be presented in the tree");
MOZ_ASSERT(mtEvent->Document(), "No document for event target");
nsEventShell::FireEvent(mtEvent);
if (aDeathGrip->IsDefunct()) {
return;
}
if (mtEvent->mTextChangeEvent) {
nsEventShell::FireEvent(mtEvent->mTextChangeEvent);
if (aDeathGrip->IsDefunct()) {
return;
}
}
if (mtEvent->IsHide()) {
@ -221,18 +233,20 @@ EventTree::Process()
if (mtEvent->mAccessible->ARIARole() == roles::MENUPOPUP) {
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
mtEvent->mAccessible);
if (aDeathGrip->IsDefunct()) {
return;
}
}
AccHideEvent* hideEvent = downcast_accEvent(mtEvent);
if (hideEvent->NeedsShutdown()) {
mtEvent->Document()->ShutdownChildrenInSubtree(mtEvent->mAccessible);
aDeathGrip->ShutdownChildrenInSubtree(mtEvent->mAccessible);
}
}
}
// Fire reorder event at last.
if (mFireReorder) {
MOZ_ASSERT(mContainer);
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_REORDER, mContainer);
mContainer->Document()->MaybeNotifyOfValueChange(mContainer);
}

View File

@ -87,7 +87,7 @@ private:
/**
* Processes the event queue and fires events.
*/
void Process();
void Process(const RefPtr<DocAccessible>& aDeathGrip);
/**
* Return an event subtree for the given accessible.

View File

@ -401,7 +401,9 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
// events causes script to run.
mObservingState = eRefreshProcessing;
mEventTree.Process();
RefPtr<DocAccessible> deathGrip(mDocument);
mEventTree.Process(deathGrip);
deathGrip = nullptr;
ProcessEventQueue();

View File

@ -377,6 +377,58 @@
}
}
function hideNDestroyDoc()
{
this.txt = null;
this.eventSeq = [
new invokerChecker(EVENT_HIDE, function() { return this.txt; }.bind(this))
];
this.invoke = function hideNDestroyDoc_invoke()
{
this.txt = getAccessible('c5').firstChild.firstChild;
this.txt.DOMNode.parentNode.removeChild(this.txt.DOMNode);
}
this.check = function hideNDestroyDoc_check()
{
getNode('c5').parentNode.removeChild(getNode('c5'));
}
this.getID = function hideNDestroyDoc_getID()
{
return "remove text node and destroy a document on hide event";
}
}
function hideHideNDestroyDoc()
{
this.target = null;
this.eventSeq = [
new invokerChecker(EVENT_HIDE, function() { return this.target; }.bind(this))
];
this.invoke = function hideHideNDestroyDoc_invoke()
{
var doc = getAccessible('c6').firstChild;
var l1 = doc.firstChild;
this.target = l1.firstChild;
var l2 = doc.lastChild;
l1.DOMNode.removeChild(l1.DOMNode.firstChild);
l2.DOMNode.removeChild(l2.DOMNode.firstChild);
}
this.check = function hideHideNDestroyDoc_check()
{
getNode('c6').parentNode.removeChild(getNode('c6'));
}
this.getID = function hideHideNDestroyDoc_getID()
{
return "remove text nodes (2 events in the queue) and destroy a document on first hide event";
}
}
/**
* Target getters.
*/
@ -507,6 +559,8 @@
gQueue.push(new insertReferredElm("testContainer3"));
gQueue.push(new showHiddenParentOfVisibleChild());
gQueue.push(new hideNDestroyDoc());
gQueue.push(new hideHideNDestroyDoc());
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -569,7 +623,10 @@
<div id="c4">
<div style="visibility:hidden" id="c4_middle">
<div style="visibility:visible" id="c4_child"></div>
</div>
<div style="visibility:visible" id="c4_child"></div>
</div>
<iframe id="c5" src="data:text/html,hey"></iframe>
<iframe id="c6" src="data:text/html,<label>l</label><label>l</label>"></iframe>
</body>
</html>