Bug 1165203 - Make calls to load() upgrade preload=none to preload=metadata; r=cpearce
authorBrian Birtles <birtles@gmail.com>
Wed, 17 Jun 2015 09:02:51 +0900
changeset 280048 34335f888c3008fb9797c5de3bcdb65890b80712
parent 280047 291f44d1891d97f1c8263718f70980655cd4f5b8
child 280049 7ccb13e479c4018ea7049ec020dff2fc412807ee
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1165203
milestone41.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 1165203 - Make calls to load() upgrade preload=none to preload=metadata; r=cpearce
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
dom/media/test/test_load.html
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -535,17 +535,17 @@ HTMLMediaElement::SetMozSrcObject(DOMMed
 {
   SetMozSrcObject(&aValue);
 }
 
 void
 HTMLMediaElement::SetMozSrcObject(DOMMediaStream* aValue)
 {
   mSrcAttrStream = aValue;
-  Load();
+  DoLoad();
 }
 
 /* readonly attribute nsIDOMHTMLMediaElement mozAutoplayEnabled; */
 NS_IMETHODIMP HTMLMediaElement::GetMozAutoplayEnabled(bool *aAutoplayEnabled)
 {
   *aAutoplayEnabled = mAutoplayEnabled;
 
   return NS_OK;
@@ -779,28 +779,39 @@ void HTMLMediaElement::QueueSelectResour
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
   RunInStableState(
     NS_NewRunnableMethod(this, &HTMLMediaElement::SelectResourceWrapper));
 }
 
 /* void load (); */
 NS_IMETHODIMP HTMLMediaElement::Load()
 {
-  if (mIsRunningLoadMethod)
+  if (mIsRunningLoadMethod) {
     return NS_OK;
+  }
+
+  mIsDoingExplicitLoad = true;
+  DoLoad();
+
+  return NS_OK;
+}
+
+void HTMLMediaElement::DoLoad()
+{
+  if (mIsRunningLoadMethod) {
+    return;
+  }
 
   SetPlayedOrSeeked(false);
   mIsRunningLoadMethod = true;
   AbortExistingLoads();
   SetPlaybackRate(mDefaultPlaybackRate);
   QueueSelectResourceTask();
   ResetState();
   mIsRunningLoadMethod = false;
-
-  return NS_OK;
 }
 
 void HTMLMediaElement::ResetState()
 {
   // There might be a pending MediaDecoder::PlaybackPositionChanged() which
   // will overwrite |mMediaInfo.mVideo.mDisplay| in UpdateMediaSize() to give
   // staled videoWidth and videoHeight. We have to call ForgetElement() here
   // such that the staled callbacks won't reach us.
@@ -823,16 +834,17 @@ static bool HasSourceChildren(nsIContent
   return false;
 }
 
 void HTMLMediaElement::SelectResourceWrapper()
 {
   SelectResource();
   mIsRunningSelectResource = false;
   mHaveQueuedSelectResource = false;
+  mIsDoingExplicitLoad = false;
 }
 
 void HTMLMediaElement::SelectResource()
 {
   if (!mSrcAttrStream && !HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
       !HasSourceChildren(this)) {
     // The media element has neither a src attribute nor any source
     // element children, abort the load.
@@ -1103,17 +1115,22 @@ void HTMLMediaElement::UpdatePreloadActi
       }
     } else {
       // Use the suggested "missing value default" of "metadata", or the value
       // specified by the media.preload.default, if present.
       nextAction = static_cast<PreloadAction>(preloadDefault);
     }
   }
 
+  if (nextAction == HTMLMediaElement::PRELOAD_NONE && mIsDoingExplicitLoad) {
+    nextAction = HTMLMediaElement::PRELOAD_METADATA;
+  }
+
   mPreloadAction = nextAction;
+
   if (nextAction == HTMLMediaElement::PRELOAD_ENOUGH) {
     if (mSuspendedForPreloadNone) {
       // Our load was previouly suspended due to the media having preload
       // value "none". The preload value has changed to preload:auto, so
       // resume the load.
       ResumeLoad(PRELOAD_ENOUGH);
     } else {
       // Preload as much of the video as we can, i.e. don't suspend after
@@ -1644,20 +1661,17 @@ NS_IMETHODIMP HTMLMediaElement::GetPlaye
 }
 
 /* void pause (); */
 void
 HTMLMediaElement::Pause(ErrorResult& aRv)
 {
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
     LOG(LogLevel::Debug, ("Loading due to Pause()"));
-    aRv = Load();
-    if (aRv.Failed()) {
-      return;
-    }
+    DoLoad();
   } else if (mDecoder) {
     mDecoder->Pause();
   }
 
   bool oldPaused = mPaused;
   mPaused = true;
   mAutoplaying = false;
   // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
@@ -2049,16 +2063,17 @@ HTMLMediaElement::HTMLMediaElement(alrea
     mIsCasting(false),
     mAudioCaptured(false),
     mPlayingBeforeSeek(false),
     mPlayingThroughTheAudioChannelBeforeSeek(false),
     mPausedForInactiveDocumentOrChannel(false),
     mEventDeliveryPaused(false),
     mWaitingFired(false),
     mIsRunningLoadMethod(false),
+    mIsDoingExplicitLoad(false),
     mIsLoadingFromSourceChildren(false),
     mDelayingLoadEvent(false),
     mIsRunningSelectResource(false),
     mHaveQueuedSelectResource(false),
     mSuspendedAfterFirstFrame(false),
     mAllowSuspendAfterFirstFrame(true),
     mHasPlayedOrSeeked(false),
     mHasSelfReference(false),
@@ -2186,20 +2201,17 @@ HTMLMediaElement::Play(ErrorResult& aRv)
     LOG(LogLevel::Debug, ("%p Blocked attempt to autoplay media.", this));
     return;
   }
 
   StopSuspendingAfterFirstFrame();
   SetPlayedOrSeeked(true);
 
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
-    aRv = Load();
-    if (aRv.Failed()) {
-      return;
-    }
+    DoLoad();
   }
   if (mSuspendedForPreloadNone) {
     ResumeLoad(PRELOAD_ENOUGH);
   }
   // Even if we just did Load() or ResumeLoad(), we could already have a decoder
   // here if we managed to clone an existing decoder.
   if (mDecoder) {
     if (mDecoder->IsEndedOrShutdown()) {
@@ -2471,17 +2483,17 @@ nsresult HTMLMediaElement::SetAttr(int32
                                    bool aNotify)
 {
   nsresult rv =
     nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
                                   aNotify);
   if (NS_FAILED(rv))
     return rv;
   if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
-    Load();
+    DoLoad();
   }
   if (aNotify && aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::autoplay) {
       StopSuspendingAfterFirstFrame();
       CheckAutoplayDataReady();
       // This attribute can affect AddRemoveSelfReference
       AddRemoveSelfReference();
       UpdatePreloadAction();
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -889,16 +889,23 @@ protected:
     PRELOAD_UNDEFINED = 0, // not determined - used only for initialization
     PRELOAD_NONE = 1,      // do not preload
     PRELOAD_METADATA = 2,  // preload only the metadata (and first frame)
     PRELOAD_ENOUGH = 3     // preload enough data to allow uninterrupted
                            // playback
   };
 
   /**
+   * The guts of Load(). Load() acts as a wrapper around this which sets
+   * mIsDoingExplicitLoad to true so that when script calls 'load()'
+   * preload-none will be automatically upgraded to preload-metadata.
+   */
+  void DoLoad();
+
+  /**
    * Suspends the load of mLoadingSrc, so that it can be resumed later
    * by ResumeLoad(). This is called when we have a media with a 'preload'
    * attribute value of 'none', during the resource selection algorithm.
    */
   void SuspendLoad();
 
   /**
    * Resumes a previously suspended load (suspended by SuspendLoad(uri)).
@@ -1278,16 +1285,20 @@ protected:
 
   // True if we've reported a "waiting" event since the last
   // readyState change to HAVE_CURRENT_DATA.
   bool mWaitingFired;
 
   // True if we're running the "load()" method.
   bool mIsRunningLoadMethod;
 
+  // True if we're running or waiting to run queued tasks due to an explicit
+  // call to "load()".
+  bool mIsDoingExplicitLoad;
+
   // True if we're loading the resource from the child source elements.
   bool mIsLoadingFromSourceChildren;
 
   // True if we're delaying the "load" event. They are delayed until either
   // an error occurs, or the first frame is loaded.
   bool mDelayingLoadEvent;
 
   // True when we've got a task queued to call SelectResource(),
--- a/dom/media/test/test_load.html
+++ b/dom/media/test/test_load.html
@@ -156,16 +156,28 @@ var gTests = [
               prependSource(src, type);
               prepended = true;
             }
           },
           false);
         document.body.appendChild(gMedia);
       },
     expectedEvents: ['loadstart', 'source_error', 'source_error']
+  }, {
+    // Test 6: (Bug 1165203) preload="none" then followed by an explicit
+    // call to load() should load metadata
+    create:
+      function(src, type) {
+        gMedia.preload = "none";
+        gMedia.src = src;
+        document.body.appendChild(gMedia);
+        addSource(src, type);
+        gMedia.load();
+      },
+    expectedEvents: ['emptied', 'ratechange',  'loadstart', 'durationchange', 'loadedmetadata', 'loadeddata']
   }
 ];
 
 function nextTest() {
   if (gMedia) {
     for (var i=0; i<gEventTypes.length; i++) {
       gMedia.removeEventListener(gEventTypes[i], listener, false);
     }