Bug 1222980 - Dispatch |QueueLoadFromSourceTask| to main thread. And end the synchronous section and asynchronously await a stable state when the src is not set. r?jwwang. draft
authorctai <ctai@mozilla.com>
Tue, 13 Dec 2016 15:45:59 +0800
changeset 449451 1f745e93060bda0de7ef604534351169fe26188f
parent 448637 42086c06f756cda7fbc25a2e7c20a5711f7e5f26
child 449452 41dcfc5e6a01ea0f27181b9d19a92d737d738379
push id38565
push userbmo:ctai@mozilla.com
push dateWed, 14 Dec 2016 06:31:56 +0000
reviewersjwwang
bugs1222980
milestone53.0a1
Bug 1222980 - Dispatch |QueueLoadFromSourceTask| to main thread. And end the synchronous section and asynchronously await a stable state when the src is not set. r?jwwang. Dispatch |QueueLoadFromSourceTask| to main thread to make sure the task will be executed later than loadstart event. And when the src get errors, we need to end the synchronous section. MozReview-Commit-ID: EQ0jVIMnqoZ
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2063,16 +2063,24 @@ void HTMLMediaElement::NotifyMediaStream
     // We are a video element and HasVideo() changed so update the screen
     // wakelock
     NotifyOwnerDocumentActivityChanged();
   }
 
   mWatchManager.ManualNotify(&HTMLMediaElement::UpdateReadyStateInternal);
 }
 
+void HTMLMediaElement::DealWithFailedElement(nsIContent* aSourceElement)
+{
+  DispatchAsyncSourceError(aSourceElement);
+  nsCOMPtr<nsIRunnable> event =
+    NewRunnableMethod(this, &HTMLMediaElement::QueueLoadFromSourceTask);
+  NS_DispatchToMainThread(event);
+}
+
 void
 HTMLMediaElement::NotifyOutputTrackStopped(DOMMediaStream* aOwningStream,
                                            TrackID aDestinationTrackID)
 {
   for (OutputMediaStream& ms : mOutputStreams) {
     if (!ms.mCapturingMediaStream) {
       continue;
     }
@@ -2120,54 +2128,54 @@ void HTMLMediaElement::LoadFromSourceChi
       ReportLoadError("MediaLoadExhaustedCandidates");
       return;
     }
 
     // Must have src attribute.
     nsAutoString src;
     if (!child->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
       ReportLoadError("MediaLoadSourceMissingSrc");
-      DispatchAsyncSourceError(child);
-      continue;
+      DealWithFailedElement(child);
+      return;
     }
 
     // If we have a type attribute, it must be a supported type.
     nsAutoString type;
     if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type)) {
       DecoderDoctorDiagnostics diagnostics;
       CanPlayStatus canPlay = GetCanPlay(type, &diagnostics);
       diagnostics.StoreFormatDiagnostics(
         OwnerDoc(), type, canPlay != CANPLAY_NO, __func__);
       if (canPlay == CANPLAY_NO) {
-        DispatchAsyncSourceError(child);
         const char16_t* params[] = { type.get(), src.get() };
         ReportLoadError("MediaLoadUnsupportedTypeAttribute", params, ArrayLength(params));
-        continue;
+        DealWithFailedElement(child);
+        return;
       }
     }
     nsAutoString media;
     HTMLSourceElement *childSrc = HTMLSourceElement::FromContent(child);
     MOZ_ASSERT(childSrc, "Expect child to be HTMLSourceElement");
     if (childSrc && !childSrc->MatchesCurrentMedia()) {
-      DispatchAsyncSourceError(child);
       const char16_t* params[] = { media.get(), src.get() };
       ReportLoadError("MediaLoadSourceMediaNotMatched", params, ArrayLength(params));
-      continue;
+      DealWithFailedElement(child);
+      return;
     }
     LOG(LogLevel::Debug, ("%p Trying load from <source>=%s type=%s media=%s", this,
       NS_ConvertUTF16toUTF8(src).get(), NS_ConvertUTF16toUTF8(type).get(),
       NS_ConvertUTF16toUTF8(media).get()));
 
     nsCOMPtr<nsIURI> uri;
     NewURIFromString(src, getter_AddRefs(uri));
     if (!uri) {
-      DispatchAsyncSourceError(child);
       const char16_t* params[] = { src.get() };
       ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
-      continue;
+      DealWithFailedElement(child);
+      return;
     }
 
     RemoveMediaElementFromURITable();
     mLoadingSrc = uri;
     mMediaSource = childSrc->GetSrcMediaSource();
     NS_ASSERTION(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING,
                  "Network state should be loading");
 
@@ -2179,17 +2187,17 @@ void HTMLMediaElement::LoadFromSourceChi
       return;
     }
 
     if (NS_SUCCEEDED(LoadResource())) {
       return;
     }
 
     // If we fail to load, loop back and try loading the next resource.
-    DispatchAsyncSourceError(child);
+    DealWithFailedElement(child);
   }
   NS_NOTREACHED("Execution should not reach here!");
 }
 
 void HTMLMediaElement::SuspendLoad()
 {
   mSuspendedForPreloadNone = true;
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -959,16 +959,24 @@ protected:
    * This is the dedicated media source failure steps.
    * Called when all potential resources are exhausted. Changes network
    * state to NETWORK_NO_SOURCE, and sends error event with code
    * MEDIA_ERR_SRC_NOT_SUPPORTED.
    */
   void NoSupportedMediaSourceError(const nsACString& aErrorDetails = nsCString());
 
   /**
+   * Per spec, Failed with elements: Queue a task, using the DOM manipulation
+   * task source, to fire a simple event named error at the candidate element.
+   * So dispatch |QueueLoadFromSourceTask| to main thread to make sure the task
+   * will be executed later than loadstart event.
+   */
+  void DealWithFailedElement(nsIContent* aSourceElement);
+
+  /**
    * Attempts to load resources from the <source> children. This is a
    * substep of the resource selection algorithm. Do not call this directly,
    * call QueueLoadFromSourceTask() instead.
    */
   void LoadFromSourceChildren();
 
   /**
    * Asynchronously awaits a stable state, and then causes