diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index a483198655..5bd0367a31 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -53,6 +53,7 @@ #include "MediaDecoder.h" #include "MediaPrefs.h" #include "MediaResource.h" +#include "MediaShutdownManager.h" #include "nsICategoryManager.h" #include "nsIContentPolicy.h" @@ -3217,6 +3218,13 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed& aNo NotifyOwnerDocumentActivityChanged(); MOZ_ASSERT(NS_IsMainThread()); + + // We initialize the MediaShutdownManager as the HTMLMediaElement is always + // constructed on the main thread, and not during stable state. + // (MediaShutdownManager make use of nsIAsyncShutdownClient which is written + // in JS) + MediaShutdownManager::InitStatics(); + mWatchManager.Watch(mDownloadSuspendedByCache, &HTMLMediaElement::UpdateReadyStateInternal); // Paradoxically, there is a self-edge whereby UpdateReadyStateInternal refuses // to run until mReadyState reaches at least HAVE_METADATA by some other means. diff --git a/dom/html/HTMLTrackElement.cpp b/dom/html/HTMLTrackElement.cpp index 07fbe2073d..710e506d6c 100644 --- a/dom/html/HTMLTrackElement.cpp +++ b/dom/html/HTMLTrackElement.cpp @@ -264,14 +264,16 @@ void HTMLTrackElement::DispatchLoadResource() { if (!mLoadResourceDispatched) { - RefPtr r = NewRunnableMethod(this, &HTMLTrackElement::LoadResource); + RefPtr listener = new WebVTTListener(this); + RefPtr r = NewRunnableMethod>(this, + &HTMLTrackElement::LoadResource, std::move(listener)); nsContentUtils::RunInStableState(r.forget()); mLoadResourceDispatched = true; } } void -HTMLTrackElement::LoadResource() +HTMLTrackElement::LoadResource(RefPtr&& aWebVTTListener) { mLoadResourceDispatched = false; @@ -317,33 +319,46 @@ HTMLTrackElement::LoadResource() } } - nsCOMPtr channel; - nsCOMPtr loadGroup = OwnerDoc()->GetDocumentLoadGroup(); - rv = NS_NewChannel(getter_AddRefs(channel), - uri, - static_cast(this), - secFlags, - nsIContentPolicy::TYPE_INTERNAL_TRACK, - loadGroup, - nullptr, // aCallbacks - nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI); - - NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv)); - - mListener = new WebVTTListener(this); + mListener = std::move(aWebVTTListener); + // This will do 6. Set the text track readiness state to loading. rv = mListener->LoadResource(); NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv)); - channel->SetNotificationCallbacks(mListener); - LOG(LogLevel::Debug, ("opening webvtt channel")); - rv = channel->AsyncOpen2(mListener); - - if (NS_FAILED(rv)) { - SetReadyState(TextTrackReadyState::FailedToLoad); + nsIDocument* doc = OwnerDoc(); + if (!doc) { return; } - mChannel = channel; + // 9. End the synchronous section, continuing the remaining steps in parallel. + NS_DispatchToMainThread(NS_NewRunnableFunction( + [ self = RefPtr(this), uri, secFlags ]() { + if (!self->mListener) { + // Shutdown got called, abort. + return; + } + nsCOMPtr channel; + nsCOMPtr loadGroup = self->OwnerDoc()->GetDocumentLoadGroup(); + nsresult rv = NS_NewChannel(getter_AddRefs(channel), + uri, + static_cast(self), + secFlags, + nsIContentPolicy::TYPE_INTERNAL_TRACK, + loadGroup, + nullptr, // aCallbacks + nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI); + NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv)); + + channel->SetNotificationCallbacks(self->mListener); + + LOG(LogLevel::Debug, ("opening webvtt channel")); + rv = channel->AsyncOpen2(self->mListener); + + if (NS_FAILED(rv)) { + self->SetReadyState(TextTrackReadyState::FailedToLoad); + return; + } + self->mChannel = channel; + })); } nsresult diff --git a/dom/html/HTMLTrackElement.h b/dom/html/HTMLTrackElement.h index 84828e4a9f..c5cab96b6a 100644 --- a/dom/html/HTMLTrackElement.h +++ b/dom/html/HTMLTrackElement.h @@ -118,9 +118,6 @@ protected: virtual JSObject* WrapNode(JSContext* aCx, JS::Handle aGivenProto) override; void OnChannelRedirect(nsIChannel* aChannel, nsIChannel* aNewChannel, uint32_t aFlags); - // Open a new channel to the HTMLTrackElement's src attribute and call - // mListener's LoadResource(). - void LoadResource(); friend class TextTrackCue; friend class WebVTTListener; @@ -134,6 +131,9 @@ protected: private: void DispatchLoadResource(); + // Open a new channel to the HTMLTrackElement's src attribute and call + // mListener's LoadResource(). + void LoadResource(RefPtr&& aWebVTTListener); bool mLoadResourceDispatched; RefPtr mWindowDestroyObserver; diff --git a/dom/html/TextTrackManager.cpp b/dom/html/TextTrackManager.cpp index 34307e47ec..1809478f2d 100644 --- a/dom/html/TextTrackManager.cpp +++ b/dom/html/TextTrackManager.cpp @@ -602,6 +602,17 @@ void TextTrackManager::TimeMarchesOn() { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + CycleCollectedJSContext* context = CycleCollectedJSContext::Get(); + if (context && context->IsInStableOrMetaStableState()) { + // FireTimeUpdate can be called while at stable state following a + // current position change which triggered a state watcher in MediaDecoder + // (see bug 1443429). + // TimeMarchesOn() will modify JS attributes which is forbidden while in + // stable state. So we dispatch a task to perform such operation later + // instead. + DispatchTimeMarchesOn(); + return; + } WEBVTT_LOG("TimeMarchesOn"); mTimeMarchesOnDispatched = false; diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 87454a4686..a6787352bc 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -457,8 +457,6 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner) mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged); mWatchManager.Watch(mIsAudioDataAudible, &MediaDecoder::NotifyAudibleStateChanged); - - MediaShutdownManager::InitStatics(); } #undef INIT_MIRROR diff --git a/dom/media/WebVTTListener.cpp b/dom/media/WebVTTListener.cpp index 18692ca273..7ff824073e 100644 --- a/dom/media/WebVTTListener.cpp +++ b/dom/media/WebVTTListener.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebVTTListener.h" +#include "mozilla/CycleCollectedJSContext.h" #include "mozilla/dom/TextTrackCue.h" #include "mozilla/dom/TextTrackRegion.h" #include "mozilla/dom/VTTRegionBinding.h" @@ -34,9 +35,22 @@ LazyLogModule gTextTrackLog("TextTrack"); WebVTTListener::WebVTTListener(HTMLTrackElement* aElement) : mElement(aElement) + , mParserWrapperError(NS_OK) { MOZ_ASSERT(mElement, "Must pass an element to the callback"); VTT_LOG("WebVTTListener created."); + MOZ_DIAGNOSTIC_ASSERT( + CycleCollectedJSContext::Get() && + !CycleCollectedJSContext::Get()->IsInStableOrMetaStableState()); + mParserWrapper = do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID, + &mParserWrapperError); + if (NS_SUCCEEDED(mParserWrapperError)) { + nsPIDOMWindowInner* window = mElement->OwnerDoc()->GetInnerWindow(); + mParserWrapperError = mParserWrapper->LoadParser(window); + } + if (NS_SUCCEEDED(mParserWrapperError)) { + mParserWrapperError = mParserWrapper->Watch(this); + } } WebVTTListener::~WebVTTListener() @@ -54,16 +68,8 @@ WebVTTListener::GetInterface(const nsIID &aIID, nsresult WebVTTListener::LoadResource() { - nsresult rv; - mParserWrapper = do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsPIDOMWindowInner* window = mElement->OwnerDoc()->GetInnerWindow(); - rv = mParserWrapper->LoadParser(window); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mParserWrapper->Watch(this); - NS_ENSURE_SUCCESS(rv, rv); + // Exit if we failed to create the WebVTTParserWrapper (vtt.jsm) + NS_ENSURE_SUCCESS(mParserWrapperError, mParserWrapperError); mElement->SetReadyState(TextTrackReadyState::Loading); return NS_OK; diff --git a/dom/media/WebVTTListener.h b/dom/media/WebVTTListener.h index 461d7f00da..03cb6e11c7 100644 --- a/dom/media/WebVTTListener.h +++ b/dom/media/WebVTTListener.h @@ -57,6 +57,7 @@ private: RefPtr mElement; nsCOMPtr mParserWrapper; + nsresult mParserWrapperError; }; } // namespace dom