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
--- 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;
}