Bug 1443429 - P3. Don't use WebVTTListener while in stable state. r=smaug
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 13 Dec 2018 20:06:02 +0000
changeset 450458 f0bd2be0b68c851510a7748ead565a5b149ce7ee
parent 450457 dd14a663cea2b64a5ef1ac702bf8e01ace067fc2
child 450459 1ae2a252d3e81d1b52fe2ef3e49c51f8c2344f1d
push id35202
push userbtara@mozilla.com
push dateFri, 14 Dec 2018 05:43:22 +0000
treeherdermozilla-central@f758b5149686 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1443429
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1443429 - P3. Don't use WebVTTListener while in stable state. r=smaug WebVTTListener is a JS wrapper around vtt.js. Differential Revision: https://phabricator.services.mozilla.com/D14282
dom/html/HTMLTrackElement.cpp
dom/html/HTMLTrackElement.h
dom/media/WebVTTListener.cpp
dom/media/WebVTTListener.h
--- a/dom/html/HTMLTrackElement.cpp
+++ b/dom/html/HTMLTrackElement.cpp
@@ -1,26 +1,25 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/dom/HTMLTrackElement.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLMediaElement.h"
-#include "mozilla/dom/HTMLTrackElement.h"
 #ifdef XP_WIN
 // HTMLTrackElement.webidl defines ERROR, but so does windows.h:
 #undef ERROR
 #endif
+#include "WebVTTListener.h"
+#include "mozilla/LoadInfo.h"
 #include "mozilla/dom/HTMLTrackElementBinding.h"
 #include "mozilla/dom/HTMLUnknownElement.h"
-#include "nsIContentPolicy.h"
-#include "mozilla/LoadInfo.h"
-#include "WebVTTListener.h"
 #include "nsAttrValueInlines.h"
 #include "nsCOMPtr.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
@@ -233,25 +232,26 @@ void HTMLTrackElement::SetSrc(const nsAS
     mChannel = nullptr;
   }
 
   DispatchLoadResource();
 }
 
 void HTMLTrackElement::DispatchLoadResource() {
   if (!mLoadResourceDispatched) {
-    RefPtr<Runnable> r =
-        NewRunnableMethod("dom::HTMLTrackElement::LoadResource", this,
-                          &HTMLTrackElement::LoadResource);
+    RefPtr<WebVTTListener> listener = new WebVTTListener(this);
+    RefPtr<Runnable> r = NewRunnableMethod<RefPtr<WebVTTListener>>(
+        "dom::HTMLTrackElement::LoadResource", this,
+        &HTMLTrackElement::LoadResource, std::move(listener));
     nsContentUtils::RunInStableState(r.forget());
     mLoadResourceDispatched = true;
   }
 }
 
-void HTMLTrackElement::LoadResource() {
+void HTMLTrackElement::LoadResource(RefPtr<WebVTTListener>&& aWebVTTListener) {
   mLoadResourceDispatched = false;
 
   // Find our 'src' url
   nsAutoString src;
   if (!GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
     return;
   }
 
@@ -287,41 +287,55 @@ void HTMLTrackElement::LoadResource() {
     } else if (CORS_USE_CREDENTIALS == corsMode) {
       secFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
     } else {
       NS_WARNING("Unknown CORS mode.");
       secFlags = nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS;
     }
   }
 
-  nsCOMPtr<nsIChannel> channel;
-  nsCOMPtr<nsILoadGroup> loadGroup = OwnerDoc()->GetDocumentLoadGroup();
-  rv = NS_NewChannel(getter_AddRefs(channel), uri, static_cast<Element*>(this),
-                     secFlags, nsIContentPolicy::TYPE_INTERNAL_TRACK,
-                     nullptr,  // PerformanceStorage
-                     loadGroup,
-                     nullptr,  // aCallbacks
-                     nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI);
-
+  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));
 
-  mListener = new WebVTTListener(this);
-  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.
+  nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
+      "dom::HTMLTrackElement::LoadResource",
+      [ self = RefPtr<HTMLTrackElement>(this), uri, secFlags ]() {
+        nsCOMPtr<nsIChannel> channel;
+        nsCOMPtr<nsILoadGroup> loadGroup =
+            self->OwnerDoc()->GetDocumentLoadGroup();
+        nsresult rv = NS_NewChannel(
+            getter_AddRefs(channel), uri, static_cast<Element*>(self), secFlags,
+            nsIContentPolicy::TYPE_INTERNAL_TRACK,
+            nullptr,  // PerformanceStorage
+            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;
+      });
+  doc->Dispatch(TaskCategory::Other, runnable.forget());
 }
 
 nsresult HTMLTrackElement::BindToTree(nsIDocument* aDocument,
                                       nsIContent* aParent,
                                       nsIContent* aBindingParent) {
   nsresult rv =
       nsGenericHTMLElement::BindToTree(aDocument, aParent, aBindingParent);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/html/HTMLTrackElement.h
+++ b/dom/html/HTMLTrackElement.h
@@ -97,32 +97,32 @@ class HTMLTrackElement final : public ns
 
  protected:
   virtual ~HTMLTrackElement();
 
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> 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;
 
   RefPtr<TextTrack> mTrack;
   nsCOMPtr<nsIChannel> mChannel;
   RefPtr<HTMLMediaElement> mMediaParent;
   RefPtr<WebVTTListener> mListener;
 
   void CreateTextTrack();
 
  private:
   void DispatchLoadResource();
+  // Open a new channel to the HTMLTrackElement's src attribute and call
+  // mListener's LoadResource().
+  void LoadResource(RefPtr<WebVTTListener>&& aWebVTTListener);
   bool mLoadResourceDispatched;
 
   RefPtr<WindowDestroyObserver> mWindowDestroyObserver;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
--- a/dom/media/WebVTTListener.cpp
+++ b/dom/media/WebVTTListener.cpp
@@ -1,22 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebVTTListener.h"
+#include "mozilla/CycleCollectedJSContext.h"
+#include "mozilla/dom/HTMLTrackElement.h"
 #include "mozilla/dom/TextTrackCue.h"
 #include "mozilla/dom/TextTrackRegion.h"
 #include "mozilla/dom/VTTRegionBinding.h"
-#include "mozilla/dom/HTMLTrackElement.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIInputStream.h"
 #include "nsIWebVTTParserWrapper.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIAsyncVerifyRedirectCallback.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION(WebVTTListener, mElement, mParserWrapper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebVTTListener)
   NS_INTERFACE_MAP_ENTRY(nsIWebVTTListener)
@@ -28,39 +29,43 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebVTTListener)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebVTTListener)
 
 LazyLogModule gTextTrackLog("TextTrack");
 #define VTT_LOG(...) MOZ_LOG(gTextTrackLog, LogLevel::Debug, (__VA_ARGS__))
 
 WebVTTListener::WebVTTListener(HTMLTrackElement* aElement)
-    : mElement(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() { VTT_LOG("WebVTTListener destroyed."); }
 
 NS_IMETHODIMP
 WebVTTListener::GetInterface(const nsIID& aIID, void** aResult) {
   return QueryInterface(aIID, aResult);
 }
 
 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;
 }
 
 NS_IMETHODIMP
 WebVTTListener::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
                                        nsIChannel* aNewChannel, uint32_t aFlags,
--- a/dom/media/WebVTTListener.h
+++ b/dom/media/WebVTTListener.h
@@ -48,14 +48,15 @@ class WebVTTListener final : public nsIW
   // List of error codes returned from the WebVTT parser that we care about.
   enum ErrorCodes { BadSignature = 0 };
   static nsresult ParseChunk(nsIInputStream* aInStream, void* aClosure,
                              const char* aFromSegment, uint32_t aToOffset,
                              uint32_t aCount, uint32_t* aWriteCount);
 
   RefPtr<HTMLTrackElement> mElement;
   nsCOMPtr<nsIWebVTTParserWrapper> mParserWrapper;
+  nsresult mParserWrapperError;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_WebVTTListener_h