Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(562)

Unified Diff: third_party/WebKit/Source/core/html/HTMLMediaElement.cpp

Issue 1522463003: Refactor resource load and resource selection algorithms as per spec (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move preloadTypeToString to anonymous namespace Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 854d8426503f2c81853c17629b5fe71399e3f62f..5a2fbe7989851f61af13f87a0fd201eb1470f3a2 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -251,6 +251,21 @@ bool canLoadURL(const KURL& url, const ContentType& contentType)
return false;
}
+String preloadTypeToString(WebMediaPlayer::Preload preloadType)
+{
+ switch (preloadType) {
+ case WebMediaPlayer::PreloadNone:
+ return "none";
+ case WebMediaPlayer::PreloadMetaData:
+ return "metadata";
+ case WebMediaPlayer::PreloadAuto:
+ return "auto";
+ }
+
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
} // anonymous namespace
void HTMLMediaElement::recordAutoplayMetric(AutoplayMetrics metric)
@@ -332,7 +347,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
, m_sentStalledEvent(false)
, m_sentEndEvent(false)
, m_closedCaptionsVisible(false)
- , m_havePreparedToPlay(false)
+ , m_ignorePreloadNone(false)
, m_tracksAreReady(true)
, m_processingPreferenceChange(false)
, m_remoteRoutesAvailable(false)
@@ -471,8 +486,8 @@ void HTMLMediaElement::didMoveToNewDocument(Document& oldDocument)
// A proper fix would provide a mechanism to allow this object to refresh
// the MediaPlayer's LocalFrame and FrameLoader references on
// document changes so that playback can be resumed properly.
- clearMediaPlayer(LoadMediaResource);
- scheduleDelayedAction(LoadMediaResource);
+ m_ignorePreloadNone = false;
+ invokeLoadAlgorithm();
// Decrement the load event delay count on oldDocument now that m_webMediaPlayer has been destroyed
// and there is no risk of dispatching a load event from within the destructor.
@@ -501,8 +516,8 @@ void HTMLMediaElement::parseAttribute(const QualifiedName& name, const AtomicStr
if (name == srcAttr) {
// Trigger a reload, as long as the 'src' attribute is present.
if (!value.isNull()) {
- clearMediaPlayer(LoadMediaResource);
- scheduleDelayedAction(LoadMediaResource);
+ m_ignorePreloadNone = false;
+ invokeLoadAlgorithm();
}
} else if (name == controlsAttr) {
UseCounter::count(document(), UseCounter::HTMLMediaElementControlsAttribute);
@@ -521,7 +536,7 @@ void HTMLMediaElement::finishParsingChildren()
HTMLElement::finishParsingChildren();
if (Traversal<HTMLTrackElement>::firstChild(*this))
- scheduleDelayedAction(LoadTextTrackResource);
+ scheduleTextTrackResourceLoad();
}
bool HTMLMediaElement::layoutObjectIsNeeded(const ComputedStyle& style)
@@ -541,8 +556,10 @@ Node::InsertionNotificationRequest HTMLMediaElement::insertedInto(ContainerNode*
HTMLElement::insertedInto(insertionPoint);
if (insertionPoint->inDocument()) {
UseCounter::count(document(), UseCounter::HTMLMediaElementInDocument);
- if (!getAttribute(srcAttr).isEmpty() && m_networkState == NETWORK_EMPTY)
- scheduleDelayedAction(LoadMediaResource);
+ if (!getAttribute(srcAttr).isEmpty() && m_networkState == NETWORK_EMPTY) {
+ m_ignorePreloadNone = false;
+ invokeLoadAlgorithm();
+ }
}
return InsertionShouldCallDidNotifySubtreeInsertions;
@@ -579,17 +596,11 @@ void HTMLMediaElement::didRecalcStyle(StyleRecalcChange)
layoutObject()->updateFromElement();
}
-void HTMLMediaElement::scheduleDelayedAction(DelayedActionType actionType)
+void HTMLMediaElement::scheduleTextTrackResourceLoad()
{
- WTF_LOG(Media, "HTMLMediaElement::scheduleDelayedAction(%p)", this);
+ WTF_LOG(Media, "HTMLMediaElement::scheduleTextTrackResourceLoad(%p)", this);
- if ((actionType & LoadMediaResource) && !(m_pendingActionFlags & LoadMediaResource)) {
- prepareForLoad();
- m_pendingActionFlags |= LoadMediaResource;
- }
-
- if (actionType & LoadTextTrackResource)
- m_pendingActionFlags |= LoadTextTrackResource;
+ m_pendingActionFlags |= LoadTextTrackResource;
if (!m_loadTimer.isActive())
m_loadTimer.startOneShot(0, BLINK_FROM_HERE);
@@ -597,7 +608,7 @@ void HTMLMediaElement::scheduleDelayedAction(DelayedActionType actionType)
void HTMLMediaElement::scheduleNextSourceChild()
{
- // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
+ // Schedule the timer to try the next <source> element WITHOUT resetting state ala invokeLoadAlgorithm.
m_pendingActionFlags |= LoadMediaResource;
m_loadTimer.startOneShot(0, BLINK_FROM_HERE);
}
@@ -710,14 +721,17 @@ void HTMLMediaElement::load()
m_autoplayMediaCounted = true;
}
- prepareForLoad();
- loadInternal();
- prepareToPlay();
+ m_ignorePreloadNone = true;
+ invokeLoadAlgorithm();
}
-void HTMLMediaElement::prepareForLoad()
+// TODO(srirama.m): Currently m_ignorePreloadNone is reset before calling
+// invokeLoadAlgorithm() in all places except load(). Move it inside here
+// once microtask is implemented for "Await a stable state" step
+// in resource selection algorithm.
+void HTMLMediaElement::invokeLoadAlgorithm()
{
- WTF_LOG(Media, "HTMLMediaElement::prepareForLoad(%p)", this);
+ WTF_LOG(Media, "HTMLMediaElement::invokeLoadAlgorithm(%p)", this);
// Perform the cleanup required for the resource load algorithm to run.
stopPeriodicTimers();
@@ -728,7 +742,6 @@ void HTMLMediaElement::prepareForLoad()
m_sentEndEvent = false;
m_sentStalledEvent = false;
m_haveFiredLoadedData = false;
- m_havePreparedToPlay = false;
m_displayMode = Unknown;
// 1 - Abort any already-running instance of the resource selection algorithm for this element.
@@ -792,14 +805,20 @@ void HTMLMediaElement::prepareForLoad()
m_autoplaying = true;
// 7 - Invoke the media element's resource selection algorithm.
+ invokeResourceSelectionAlgorithm();
// 8 - Note: Playback of any previously playing media resource for this element stops.
+}
+void HTMLMediaElement::invokeResourceSelectionAlgorithm()
+{
+ WTF_LOG(Media, "HTMLMediaElement::invokeResourceSelectionAlgorithm(%p)", this);
// The resource selection algorithm
// 1 - Set the networkState to NETWORK_NO_SOURCE
setNetworkState(NETWORK_NO_SOURCE);
- // 2 - Asynchronously await a stable state.
+ // 2 - Set the element's show poster flag to true
+ // TODO(srirama.m): Introduce show poster flag and update it as per spec
m_playedTimeRanges = TimeRanges::create();
@@ -808,12 +827,15 @@ void HTMLMediaElement::prepareForLoad()
m_lastSeekTime = 0;
m_duration = std::numeric_limits<double>::quiet_NaN();
- // The spec doesn't say to block the load event until we actually run the asynchronous section
- // algorithm, but do it now because we won't start that until after the timer fires and the
- // event may have already fired by then.
+ // 3 - Set the media element's delaying-the-load-event flag to true (this delays the load event)
setShouldDelayLoadEvent(true);
if (mediaControls())
mediaControls()->reset();
+
+ // 4 - Await a stable state, allowing the task that invoked this algorithm to continue
+ // TODO(srirama.m): Remove scheduleNextSourceChild() and post a microtask instead.
+ // See http://crbug.com/593289 for more details.
+ scheduleNextSourceChild();
}
void HTMLMediaElement::loadInternal()
@@ -976,7 +998,7 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
if (attemptLoad && canLoadURL(url, contentType)) {
ASSERT(!webMediaPlayer());
- if (!m_havePreparedToPlay && effectivePreloadType() == WebMediaPlayer::PreloadNone) {
+ if (effectivePreloadType() == WebMediaPlayer::PreloadNone) {
WTF_LOG(Media, "HTMLMediaElement::loadResource(%p) : Delaying load because preload == 'none'", this);
deferLoad();
} else {
@@ -1054,7 +1076,7 @@ void HTMLMediaElement::setPlayerPreload()
if (m_webMediaPlayer)
m_webMediaPlayer->setPreload(effectivePreloadType());
- if (loadIsDeferred() && preloadType() != WebMediaPlayer::PreloadNone)
+ if (loadIsDeferred() && effectivePreloadType() != WebMediaPlayer::PreloadNone)
startDeferredLoad();
}
@@ -1607,15 +1629,11 @@ bool HTMLMediaElement::supportsSave() const
return webMediaPlayer() && webMediaPlayer()->supportsSave();
}
-void HTMLMediaElement::prepareToPlay()
+void HTMLMediaElement::setIgnorePreloadNone()
{
- WTF_LOG(Media, "HTMLMediaElement::prepareToPlay(%p)", this);
- if (m_havePreparedToPlay)
- return;
- m_havePreparedToPlay = true;
-
- if (loadIsDeferred())
- startDeferredLoad();
+ WTF_LOG(Media, "HTMLMediaElement::setIgnorePreloadNone(%p)", this);
+ m_ignorePreloadNone = true;
+ setPlayerPreload();
}
void HTMLMediaElement::seek(double time)
@@ -1626,9 +1644,8 @@ void HTMLMediaElement::seek(double time)
if (m_readyState == HAVE_NOTHING)
return;
- // If the media engine has been told to postpone loading data, let it go ahead now.
- if (preloadType() < WebMediaPlayer::PreloadAuto && m_readyState < HAVE_FUTURE_DATA)
- prepareToPlay();
+ // Ignore preload none and start load if necessary.
+ setIgnorePreloadNone();
// Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
refreshCachedTime();
@@ -1888,17 +1905,7 @@ bool HTMLMediaElement::shouldAutoplay(const RecordMetricsBehavior recordMetrics)
String HTMLMediaElement::preload() const
{
- switch (preloadType()) {
- case WebMediaPlayer::PreloadNone:
- return "none";
- case WebMediaPlayer::PreloadMetaData:
- return "metadata";
- case WebMediaPlayer::PreloadAuto:
- return "auto";
- }
-
- ASSERT_NOT_REACHED();
- return String();
+ return preloadTypeToString(preloadType());
}
void HTMLMediaElement::setPreload(const AtomicString& preload)
@@ -1942,9 +1949,21 @@ WebMediaPlayer::Preload HTMLMediaElement::preloadType() const
return WebMediaPlayer::PreloadAuto;
}
+String HTMLMediaElement::effectivePreload() const
+{
+ return preloadTypeToString(effectivePreloadType());
+}
+
WebMediaPlayer::Preload HTMLMediaElement::effectivePreloadType() const
{
- return autoplay() ? WebMediaPlayer::PreloadAuto : preloadType();
+ if (autoplay())
+ return WebMediaPlayer::PreloadAuto;
+
+ WebMediaPlayer::Preload preload = preloadType();
+ if (m_ignorePreloadNone && preload == WebMediaPlayer::PreloadNone)
+ return WebMediaPlayer::PreloadMetaData;
+
+ return preload;
}
ScriptPromise HTMLMediaElement::playForBindings(ScriptState* scriptState)
@@ -2016,7 +2035,7 @@ void HTMLMediaElement::playInternal()
// 4.8.10.9. Playing the media resource
if (m_networkState == NETWORK_EMPTY)
- scheduleDelayedAction(LoadMediaResource);
+ invokeResourceSelectionAlgorithm();
// Generally "ended" and "looping" are exclusive. Here, the loop attribute
// is ignored to seek back to start in case loop was set after playback
@@ -2039,6 +2058,7 @@ void HTMLMediaElement::playInternal()
m_autoplaying = false;
+ setIgnorePreloadNone();
updatePlayState();
}
@@ -2079,7 +2099,7 @@ void HTMLMediaElement::pauseInternal()
WTF_LOG(Media, "HTMLMediaElement::pauseInternal(%p)", this);
if (m_networkState == NETWORK_EMPTY)
- scheduleDelayedAction(LoadMediaResource);
+ invokeResourceSelectionAlgorithm();
m_autoplayHelper.pauseMethodCalled();
@@ -2415,7 +2435,7 @@ void HTMLMediaElement::addTextTrack(WebInbandTextTrack* webTrack)
// 7. Set the new text track's mode to the mode consistent with the user's preferences and the requirements of
// the relevant specification for the data.
// - This will happen in honorUserPreferencesForAutomaticTextTrackSelection()
- scheduleDelayedAction(LoadTextTrackResource);
+ scheduleTextTrackResourceLoad();
// 8. Add the new text track to the media element's list of text tracks.
// 9. Fire an event with the name addtrack, that does not bubble and is not cancelable, and that uses the TrackEvent
@@ -2535,7 +2555,7 @@ void HTMLMediaElement::didAddTrackElement(HTMLTrackElement* trackElement)
// Do not schedule the track loading until parsing finishes so we don't start before all tracks
// in the markup have been added.
if (isFinishedParsingChildren())
- scheduleDelayedAction(LoadTextTrackResource);
+ scheduleTextTrackResourceLoad();
}
void HTMLMediaElement::didRemoveTrackElement(HTMLTrackElement* trackElement)
@@ -2720,17 +2740,20 @@ void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
// attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke
// the media element's resource selection algorithm.
if (getNetworkState() == HTMLMediaElement::NETWORK_EMPTY) {
- scheduleDelayedAction(LoadMediaResource);
+ invokeResourceSelectionAlgorithm();
+ // Ignore current |m_nextChildNodeToConsider| and consider |source|.
m_nextChildNodeToConsider = source;
return;
}
if (m_currentSourceNode && source == m_currentSourceNode->nextSibling()) {
WTF_LOG(Media, "HTMLMediaElement::sourceWasAdded(%p) - <source> inserted immediately after current source", this);
+ // Ignore current |m_nextChildNodeToConsider| and consider |source|.
m_nextChildNodeToConsider = source;
return;
}
+ // Consider current |m_nextChildNodeToConsider| as it is already in the middle of processing.
if (m_nextChildNodeToConsider)
return;
@@ -3050,9 +3073,6 @@ void HTMLMediaElement::updatePlayState()
if (time > m_lastSeekTime)
addPlayedRange(m_lastSeekTime, time);
- if (couldPlayIfEnoughData())
- prepareToPlay();
-
if (mediaControls())
mediaControls()->playbackStopped();
}
@@ -3076,7 +3096,7 @@ void HTMLMediaElement::clearMediaPlayerAndAudioSourceProviderClientWithoutLockin
}
}
-void HTMLMediaElement::clearMediaPlayer(int flags)
+void HTMLMediaElement::clearMediaPlayer()
{
forgetResourceSpecificTracks();
@@ -3092,7 +3112,7 @@ void HTMLMediaElement::clearMediaPlayer(int flags)
stopPeriodicTimers();
m_loadTimer.stop();
- m_pendingActionFlags &= ~flags;
+ m_pendingActionFlags = 0;
m_loadState = WaitingForSource;
// We can't cast if we don't have a media player.
@@ -3115,8 +3135,8 @@ void HTMLMediaElement::stop()
cancelPendingEventsAndCallbacks();
m_asyncEventQueue->close();
- // Stop the playback without generating events
- clearMediaPlayer(-1);
+ // Clear everything in the Media Element
+ clearMediaPlayer();
m_readyState = HAVE_NOTHING;
m_readyStateMaximum = HAVE_NOTHING;
setNetworkState(NETWORK_EMPTY);
@@ -3487,7 +3507,7 @@ void* HTMLMediaElement::preDispatchEventHandler(Event* event)
return nullptr;
}
-// TODO(srirama.m): Refactor this and clearMediaPlayer to the extent possible.
+// TODO(srirama.m): Merge it to resetMediaElement if possible and remove it.
void HTMLMediaElement::resetMediaPlayerAndMediaSource()
{
closeMediaSource();
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLMediaElement.h ('k') | third_party/WebKit/Source/core/testing/Internals.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698