Bug 1409985 - Don't fire DOMEvent during StableState. r=smaug

This commit is contained in:
Bevis Tseng 2017-10-19 18:20:31 +08:00
parent 89df96b890
commit 6115852e16
6 changed files with 81 additions and 11 deletions

View File

@ -5829,6 +5829,14 @@ nsContentUtils::RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable)
CycleCollectedJSContext::Get()->RunInMetastableState(Move(aRunnable));
}
/* static */
bool
nsContentUtils::IsInStableOrMetaStableState()
{
MOZ_ASSERT(CycleCollectedJSContext::Get(), "Must be on a script thread!");
return CycleCollectedJSContext::Get()->IsInStableOrMetaStableState();
}
/* static */
nsISerialEventTarget*
nsContentUtils::GetStableStateEventTarget()

View File

@ -1972,6 +1972,11 @@ public:
*/
static void RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable);
/**
* Returns true if we are doing StableState/MetastableState.
*/
static bool IsInStableOrMetaStableState();
/**
* Returns a nsISerialEventTarget which will run any event dispatched to it
* once the event loop has reached a "stable state". Runnables dispatched to

View File

@ -601,6 +601,10 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
NS_ENSURE_TRUE(aEvent->mMessage || !aDOMEvent || aTargets,
NS_ERROR_DOM_INVALID_STATE_ERR);
// Events shall not be fired while we are in stable state to prevent anything
// visible from the scripts.
MOZ_ASSERT(!nsContentUtils::IsInStableOrMetaStableState());
#ifdef MOZ_TASK_TRACER
if (MOZ_UNLIKELY(mozilla::tasktracer::IsStartLogging())) {
nsAutoCString eventType;

View File

@ -158,7 +158,18 @@ class MediaDecoder::BackgroundVideoDecodingPermissionObserver final :
if (observerService) {
observerService->AddObserver(this, "unselected-tab-hover", false);
mIsRegisteredForEvent = true;
EnableEvent();
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(TaskCategory::Other,
NewRunnableMethod(
"MediaDecoder::BackgroundVideoDecodingPermissionObserver::EnableEvent",
this, &MediaDecoder::BackgroundVideoDecodingPermissionObserver::EnableEvent));
}
} else {
EnableEvent();
}
}
}
@ -170,7 +181,18 @@ class MediaDecoder::BackgroundVideoDecodingPermissionObserver final :
mIsRegisteredForEvent = false;
mDecoder->mIsBackgroundVideoDecodingAllowed = false;
mDecoder->UpdateVideoDecodeMode();
DisableEvent();
if (nsContentUtils::IsInStableOrMetaStableState()) {
// Events shall not be fired synchronously to prevent anything visible
// from the scripts while we are in stable state.
if (nsCOMPtr<nsIDocument> doc = GetOwnerDoc()) {
doc->Dispatch(TaskCategory::Other,
NewRunnableMethod(
"MediaDecoder::BackgroundVideoDecodingPermissionObserver::DisableEvent",
this, &MediaDecoder::BackgroundVideoDecodingPermissionObserver::DisableEvent));
}
} else {
DisableEvent();
}
}
}
private:

View File

@ -61,18 +61,35 @@ public:
switch (event) {
case MediaStreamGraphEvent::EVENT_FINISHED:
{
RefPtr<SynthStreamListener> self = this;
if (!mStarted) {
mStarted = true;
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
NewRunnableMethod("dom::SynthStreamListener::DoNotifyStarted",
this,
&SynthStreamListener::DoNotifyStarted));
NS_NewRunnableFunction(
"dom::SynthStreamListener::NotifyEvent",
[self] {
// "start" event will be fired in DoNotifyStarted() which is
// not allowed in stable state, so we do it asynchronously in
// next run.
NS_DispatchToMainThread(NewRunnableMethod(
"dom::SynthStreamListener::DoNotifyStarted",
self,
&SynthStreamListener::DoNotifyStarted));
}));
}
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
NewRunnableMethod("dom::SynthStreamListener::DoNotifyFinished",
this,
&SynthStreamListener::DoNotifyFinished));
NS_NewRunnableFunction(
"dom::SynthStreamListener::NotifyEvent",
[self] {
// "end" event will be fired in DoNotifyFinished() which is
// not allowed in stable state, so we do it asynchronously in
// next run.
NS_DispatchToMainThread(NewRunnableMethod(
"dom::SynthStreamListener::DoNotifyFinished",
self,
&SynthStreamListener::DoNotifyFinished));
}));
}
break;
case MediaStreamGraphEvent::EVENT_REMOVED:
@ -89,10 +106,19 @@ public:
{
if (aBlocked == MediaStreamListener::UNBLOCKED && !mStarted) {
mStarted = true;
RefPtr<SynthStreamListener> self = this;
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
NewRunnableMethod("dom::SynthStreamListener::DoNotifyStarted",
this,
&SynthStreamListener::DoNotifyStarted));
NS_NewRunnableFunction(
"dom::SynthStreamListener::NotifyBlockingChanged",
[self] {
// "start" event will be fired in DoNotifyStarted() which is
// not allowed in stable state, so we do it asynchronously in
// next run.
NS_DispatchToMainThread(NewRunnableMethod(
"dom::SynthStreamListener::DoNotifyStarted",
self,
&SynthStreamListener::DoNotifyStarted));
}));
}
}

View File

@ -242,6 +242,11 @@ public:
void DispatchMicroTaskRunnable(already_AddRefed<MicroTaskRunnable> aRunnable);
bool IsInStableOrMetaStableState()
{
return mDoingStableStates;
}
// Storage for watching rejected promises waiting for some client to
// consume their rejection.
// Promises in this list have been rejected in the last turn of the