Bug 1277813 - Consider HTMLMediaElement.load() in user generated event handler to allow autoplay. r?kinetik draft
authorChris Pearce <cpearce@mozilla.com>
Tue, 12 Jul 2016 16:25:33 +1200
changeset 387326 506a1c92e83e179dd56242c89a704aef569c8187
parent 386845 1e8c30862bba5c02f97c232e8f02d77687ac4f4f
child 525332 5261e4033e7613d141a6cfa9338306c93ba3355c
push id22940
push usercpearce@mozilla.com
push dateWed, 13 Jul 2016 21:09:09 +0000
reviewerskinetik
bugs1277813
milestone50.0a1
Bug 1277813 - Consider HTMLMediaElement.load() in user generated event handler to allow autoplay. r?kinetik This is so that if media autoplay is disabled, a site can capture user intent to play in their click handlers by calling load() on an empty video element to "bless" the video element with the ability to play later when the video has loaded. Large video sites typically have a catalog view of videos to chose from on their main page, and when the user clicks on one, with this patch, the site can bless a video element so that it will play by beginning the load of that video in the click handler. Often these sites do a bunch of asynchronous things before they actually get around to playing the video, they don't call play in the click handler, so we need another way to bless the videos so they can play. We allow seeks in a click handler to capture user intent to play, so I don't see why we should not also allow a load() to capture user intent. MozReview-Commit-ID: KzjNcn3s6od
dom/html/HTMLMediaElement.cpp
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1079,34 +1079,63 @@ void HTMLMediaElement::QueueSelectResour
   if (mHaveQueuedSelectResource)
     return;
   mHaveQueuedSelectResource = true;
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
   RefPtr<Runnable> r = NewRunnableMethod(this, &HTMLMediaElement::SelectResourceWrapper);
   RunInStableState(r);
 }
 
+static bool HasSourceChildren(nsIContent* aElement)
+{
+  for (nsIContent* child = aElement->GetFirstChild();
+       child;
+       child = child->GetNextSibling()) {
+    if (child->IsHTMLElement(nsGkAtoms::source))
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
 NS_IMETHODIMP HTMLMediaElement::Load()
 {
+  LOG(LogLevel::Debug,
+      ("%p Load() hasSrcAttrStream=%d hasSrcAttr=%d hasSourceChildren=%d "
+       "handlingInput=%d isCallerChromeOrNative=%d",
+       this, !!mSrcAttrStream, HasAttr(kNameSpaceID_None, nsGkAtoms::src),
+       HasSourceChildren(this), EventStateManager::IsHandlingUserInput(),
+       nsContentUtils::LegacyIsCallerChromeOrNativeCode()));
+
   if (mIsRunningLoadMethod) {
     return NS_OK;
   }
 
   mIsDoingExplicitLoad = true;
   DoLoad();
 
   return NS_OK;
 }
 
 void HTMLMediaElement::DoLoad()
 {
   if (mIsRunningLoadMethod) {
     return;
   }
 
+  // Detect if user has interacted with element so that play will not be
+  // blocked when initiated by a script. This enables sites to capture user
+  // intent to play by calling load() in the click handler of a "catalog
+  // view" of a gallery of videos.
+  if (EventStateManager::IsHandlingUserInput() ||
+      nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
+    mHasUserInteraction = true;
+  }
+
   SetPlayedOrSeeked(false);
   mIsRunningLoadMethod = true;
   AbortExistingLoads();
   SetPlaybackRate(mDefaultPlaybackRate);
   QueueSelectResourceTask();
   ResetState();
   mIsRunningLoadMethod = false;
 }
@@ -1118,29 +1147,16 @@ void HTMLMediaElement::ResetState()
   // staled videoWidth and videoHeight. We have to call ForgetElement() here
   // such that the staled callbacks won't reach us.
   if (mVideoFrameContainer) {
     mVideoFrameContainer->ForgetElement();
     mVideoFrameContainer = nullptr;
   }
 }
 
-static bool HasSourceChildren(nsIContent* aElement)
-{
-  for (nsIContent* child = aElement->GetFirstChild();
-       child;
-       child = child->GetNextSibling()) {
-    if (child->IsHTMLElement(nsGkAtoms::source))
-    {
-      return true;
-    }
-  }
-  return false;
-}
-
 void HTMLMediaElement::SelectResourceWrapper()
 {
   SelectResource();
   mIsRunningSelectResource = false;
   mHaveQueuedSelectResource = false;
   mIsDoingExplicitLoad = false;
 }