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 06d4a93b6dfca9cb3d42b26427ecb7be2d3f6673..dda056c1086c4dfd11fbd1a94d90f1a1b494d537 100644 |
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp |
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp |
@@ -791,6 +791,9 @@ void HTMLMediaElement::invokeLoadAlgorithm() |
// one of the task queues, then remove those tasks. |
cancelPendingEventsAndCallbacks(); |
+ for (auto& resolver : m_playPromiseResolvers) |
+ m_playPromiseRejectList.append(resolver); |
philipj_slow
2016/04/06 14:12:59
m_playPromiseRejectList.append(m_playPromiseResolv
mlamouri (slow - plz ping)
2016/04/12 14:36:20
Done. Here and other places.
|
+ m_playPromiseResolvers.clear(); |
rejectPlayPromises(AbortError, "The play() request was interrupted by a new load request."); |
// 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue |
@@ -2011,8 +2014,20 @@ WebMediaPlayer::Preload HTMLMediaElement::effectivePreloadType() const |
ScriptPromise HTMLMediaElement::playForBindings(ScriptState* scriptState) |
{ |
+ // We have to share the same logic for internal and external callers. The |
+ // internal callers do not want to receive a Promise back but when ::play() |
+ // is called, |m_playPromiseResolvers| needs to be populated. What this code do |
philipj_slow
2016/04/06 14:12:59
s/do then/does/
mlamouri (slow - plz ping)
2016/04/12 14:36:20
Done.
|
+ // then is to populate |m_playPromiseResolvers| before calling ::play() and remove |
+ // the Promise if ::play() failed. |
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
+ ScriptPromise promise = resolver->promise(); |
+ m_playPromiseResolvers.append(resolver); |
philipj_slow
2016/04/06 14:12:59
I don't follow why this change was needed. Does it
mlamouri (slow - plz ping)
2016/04/12 14:36:20
Assume the media is already playing. It will resol
|
+ |
Nullable<ExceptionCode> code = play(); |
if (!code.isNull()) { |
+ ASSERT(!m_playPromiseResolvers.isEmpty()); |
+ m_playPromiseResolvers.removeLast(); |
+ |
String message; |
switch (code.get()) { |
case NotAllowedError: |
@@ -2027,10 +2042,6 @@ ScriptPromise HTMLMediaElement::playForBindings(ScriptState* scriptState) |
return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(code.get(), message)); |
} |
- ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
- ScriptPromise promise = resolver->promise(); |
- |
- m_playResolvers.append(resolver); |
return promise; |
} |
@@ -3633,7 +3644,9 @@ DEFINE_TRACE(HTMLMediaElement) |
visitor->trace(m_cueTimeline); |
visitor->trace(m_textTracks); |
visitor->trace(m_textTracksWhenResourceSelectionBegan); |
- visitor->trace(m_playResolvers); |
+ visitor->trace(m_playPromiseResolvers); |
+ visitor->trace(m_playPromiseResolveList); |
+ visitor->trace(m_playPromiseRejectList); |
visitor->trace(m_audioSourceProvider); |
visitor->trace(m_autoplayHelperClient); |
visitor->trace(m_autoplayHelper); |
@@ -3715,10 +3728,20 @@ void HTMLMediaElement::triggerAutoplayViewportCheckForTesting() |
void HTMLMediaElement::scheduleResolvePlayPromises() |
{ |
- // Per spec, if there are two tasks in the queue, the first task will remove |
- // all the pending promises making the second task useless unless a promise |
- // can be added between the first and second task being run which is not |
- // possible at the moment. |
+ // TODO(mlamouri): per spec, we should create a new task but we can't create |
+ // a new cancellable task without cancelling the previous one. There are two |
+ // approaches then: cancel the previous task and create a new one with the |
+ // appended promise list or append the new promise to the current list. The |
philipj_slow
2016/04/06 14:12:59
Hmm, so these are two decidedly not great options.
mlamouri (slow - plz ping)
2016/04/12 14:36:20
I believe I'm doing what you are suggesting here o
|
+ // former approach is prefered because it might be the less observable |
+ // change. |
+ ASSERT(m_playPromiseResolveList.isEmpty() || m_playPromiseResolveTask->isPending()); |
+ if (m_playPromiseResolvers.isEmpty()) |
+ return; |
+ |
+ for (auto& resolver : m_playPromiseResolvers) |
+ m_playPromiseResolveList.append(resolver); |
+ m_playPromiseResolvers.clear(); |
+ |
if (m_playPromiseResolveTask->isPending()) |
return; |
@@ -3727,10 +3750,20 @@ void HTMLMediaElement::scheduleResolvePlayPromises() |
void HTMLMediaElement::scheduleRejectPlayPromises(ExceptionCode code) |
{ |
- // Per spec, if there are two tasks in the queue, the first task will remove |
- // all the pending promises making the second task useless unless a promise |
- // can be added between the first and second task being run which is not |
- // possible at the moment. |
+ // TODO(mlamouri): per spec, we should create a new task but we can't create |
+ // a new cancellable task without cancelling the previous one. There are two |
+ // approaches then: cancel the previous task and create a new one with the |
+ // appended promise list or append the new promise to the current list. The |
+ // former approach is prefered because it might be the less observable |
+ // change. |
+ ASSERT(m_playPromiseRejectList.isEmpty() || m_playPromiseRejectTask->isPending()); |
+ if (m_playPromiseResolvers.isEmpty()) |
+ return; |
+ |
+ for (auto& resolver : m_playPromiseResolvers) |
+ m_playPromiseRejectList.append(resolver); |
+ m_playPromiseResolvers.clear(); |
+ |
if (m_playPromiseRejectTask->isPending()) |
return; |
@@ -3748,10 +3781,10 @@ void HTMLMediaElement::scheduleNotifyPlaying() |
void HTMLMediaElement::resolvePlayPromises() |
{ |
- for (auto& resolver: m_playResolvers) |
+ for (auto& resolver: m_playPromiseResolveList) |
resolver->resolve(); |
- m_playResolvers.clear(); |
+ m_playPromiseResolveList.clear(); |
} |
void HTMLMediaElement::rejectPlayPromises() |
@@ -3770,10 +3803,10 @@ void HTMLMediaElement::rejectPlayPromises(ExceptionCode code, const String& mess |
{ |
ASSERT(code == AbortError || code == NotSupportedError); |
- for (auto& resolver: m_playResolvers) |
+ for (auto& resolver: m_playPromiseRejectList) |
resolver->reject(DOMException::create(code, message)); |
- m_playResolvers.clear(); |
+ m_playPromiseRejectList.clear(); |
} |
void HTMLMediaElement::clearWeakMembers(Visitor* visitor) |