Changeset 226059 in webkit
- Timestamp:
- Dec 18, 2017 9:43:50 AM (6 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r226054 r226059 1 2017-12-18 Jer Noble <jer.noble@apple.com> 2 3 Playing media elements which call "pause(); play()" will have the play promise rejected. 4 https://bugs.webkit.org/show_bug.cgi?id=180781 5 6 Reviewed by Eric Carlson. 7 8 * media/audio-dealloc-crash.html: 9 * media/video-pause-play-resolve-expected.txt: Added. 10 * media/video-pause-play-resolve.html: Added. 11 1 12 2017-12-18 Daniel Bates <dabates@apple.com> 2 13 -
trunk/LayoutTests/http/tests/security/video-cross-origin-caching-expected.txt
r222270 r226059 1 CONSOLE MESSAGE: Unhandled Promise Rejection: AbortError: The operation was aborted.2 1 3 2 This test passes if you do not see a CORS error. -
trunk/LayoutTests/media/audio-dealloc-crash.html
r211659 r226059 10 10 runWithKeyDown(() => { 11 11 document.body.innerHTML = '<audio></audio>'; 12 document.body.childNodes[0].play() ;12 document.body.childNodes[0].play().catch(error => {}); 13 13 document.body.innerHTML = ''; 14 14 gc(); -
trunk/Source/WebCore/ChangeLog
r226048 r226059 1 2017-12-18 Jer Noble <jer.noble@apple.com> 2 3 Playing media elements which call "pause(); play()" will have the play promise rejected. 4 https://bugs.webkit.org/show_bug.cgi?id=180781 5 6 Reviewed by Eric Carlson. 7 8 Test: media/video-pause-play-resolve.html 9 10 When scheduling a rejection or resolution of existing play promises, move() the existing 11 promises into the block. This ensures that valid promises aren't added to the play promise 12 vector between when a rejection is scheduled and when it runs. 13 14 Drive-by fix: Don't return false from playInternal() just so the newly created promise will 15 get rejected. The pause() command will reject the promise, so just make sure it's added to 16 the m_pendingPlayPromises before calling playInternal(). 17 18 Drive-by fix #2: The spec referenced by playInternal() and pauseInternal() doesn't say to 19 call the "Media Element Load Algorithm" (i.e., prepareForLoad()); it says to call the 20 "Resource Selection Algorithm" (i.e., selectMediaResource()). But fixing this bug caused 21 an assertion crash when the resource selection task was fired and m_player was null. This 22 was because the algorithm is being run at stop() time due to stop() calling pause(). The 23 solution to this ASSERT is to stop the m_resourceSelectionTaskQueue in stop(). 24 25 * html/HTMLMediaElement.cpp: 26 (WebCore::HTMLMediaElement::scheduleRejectPendingPlayPromises): 27 (WebCore::HTMLMediaElement::rejectPendingPlayPromises): 28 (WebCore::HTMLMediaElement::resolvePendingPlayPromises): 29 (WebCore::HTMLMediaElement::scheduleNotifyAboutPlaying): 30 (WebCore::HTMLMediaElement::notifyAboutPlaying): 31 (WebCore::HTMLMediaElement::noneSupported): 32 (WebCore::HTMLMediaElement::cancelPendingEventsAndCallbacks): 33 (WebCore::HTMLMediaElement::play): 34 (WebCore::HTMLMediaElement::playInternal): 35 (WebCore::HTMLMediaElement::pauseInternal): 36 (WebCore::HTMLMediaElement::stop): 37 * html/HTMLMediaElement.h: 38 1 39 2017-12-18 Daniel Bates <dabates@apple.com> 2 40 -
trunk/Source/WebCore/html/HTMLMediaElement.cpp
r225830 r226059 1073 1073 void HTMLMediaElement::scheduleResolvePendingPlayPromises() 1074 1074 { 1075 m_promiseTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::resolvePendingPlayPromises, this)); 1076 } 1077 1078 void HTMLMediaElement::rejectPendingPlayPromises(DOMException& error) 1079 { 1080 Vector<DOMPromiseDeferred<void>> pendingPlayPromises = WTFMove(m_pendingPlayPromises); 1081 1075 m_promiseTaskQueue.enqueueTask([this, pendingPlayPromises = WTFMove(m_pendingPlayPromises)] () mutable { 1076 resolvePendingPlayPromises(WTFMove(pendingPlayPromises)); 1077 }); 1078 } 1079 1080 void HTMLMediaElement::scheduleRejectPendingPlayPromises(Ref<DOMException>&& error) 1081 { 1082 m_promiseTaskQueue.enqueueTask([this, error = WTFMove(error), pendingPlayPromises = WTFMove(m_pendingPlayPromises)] () mutable { 1083 rejectPendingPlayPromises(WTFMove(pendingPlayPromises), WTFMove(error)); 1084 }); 1085 } 1086 1087 void HTMLMediaElement::rejectPendingPlayPromises(PlayPromiseVector&& pendingPlayPromises, Ref<DOMException>&& error) 1088 { 1082 1089 for (auto& promise : pendingPlayPromises) 1083 1090 promise.rejectType<IDLInterface<DOMException>>(error); 1084 1091 } 1085 1092 1086 void HTMLMediaElement::resolvePendingPlayPromises() 1087 { 1088 Vector<DOMPromiseDeferred<void>> pendingPlayPromises = WTFMove(m_pendingPlayPromises); 1089 1093 void HTMLMediaElement::resolvePendingPlayPromises(PlayPromiseVector&& pendingPlayPromises) 1094 { 1090 1095 for (auto& promise : pendingPlayPromises) 1091 1096 promise.resolve(); … … 1094 1099 void HTMLMediaElement::scheduleNotifyAboutPlaying() 1095 1100 { 1096 m_promiseTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::notifyAboutPlaying, this)); 1097 } 1098 1099 void HTMLMediaElement::notifyAboutPlaying() 1101 m_promiseTaskQueue.enqueueTask([this, pendingPlayPromises = WTFMove(m_pendingPlayPromises)] () mutable { 1102 notifyAboutPlaying(WTFMove(pendingPlayPromises)); 1103 }); 1104 } 1105 1106 void HTMLMediaElement::notifyAboutPlaying(PlayPromiseVector&& pendingPlayPromises) 1100 1107 { 1101 1108 Ref<HTMLMediaElement> protectedThis(*this); // The 'playing' event can make arbitrary DOM mutations. 1102 1109 m_playbackStartedTime = currentMediaTime().toDouble(); 1103 1110 dispatchEvent(Event::create(eventNames().playingEvent, false, true)); 1104 resolvePendingPlayPromises( );1111 resolvePendingPlayPromises(WTFMove(pendingPlayPromises)); 1105 1112 1106 1113 m_hasEverNotifiedAboutPlaying = true; … … 2169 2176 scheduleEvent(eventNames().errorEvent); 2170 2177 2171 rejectPendingPlayPromises( DOMException::create(NotSupportedError));2178 rejectPendingPlayPromises(WTFMove(m_pendingPlayPromises), DOMException::create(NotSupportedError)); 2172 2179 2173 2180 #if ENABLE(MEDIA_SOURCE) … … 2232 2239 source.cancelPendingErrorEvent(); 2233 2240 2234 rejectPendingPlayPromises( DOMException::create(AbortError));2241 rejectPendingPlayPromises(WTFMove(m_pendingPlayPromises), DOMException::create(AbortError)); 2235 2242 } 2236 2243 … … 3419 3426 removeBehaviorsRestrictionsAfterFirstUserGesture(); 3420 3427 3421 if (!playInternal()) {3422 promise.reject(NotAllowedError);3423 return;3424 }3425 3426 3428 m_pendingPlayPromises.append(WTFMove(promise)); 3429 playInternal(); 3427 3430 } 3428 3431 … … 3443 3446 } 3444 3447 3445 boolHTMLMediaElement::playInternal()3448 void HTMLMediaElement::playInternal() 3446 3449 { 3447 3450 ALWAYS_LOG(LOGIDENTIFIER); … … 3449 3452 if (!m_mediaSession->clientWillBeginPlayback()) { 3450 3453 ALWAYS_LOG(LOGIDENTIFIER, " returning because of interruption"); 3451 return true; // Treat as success because we will begin playback on cessation of the interruption.3454 return; // Treat as success because we will begin playback on cessation of the interruption. 3452 3455 } 3453 3456 3454 3457 // 4.8.10.9. Playing the media resource 3455 3458 if (!m_player || m_networkState == NETWORK_EMPTY) 3456 prepareForLoad();3459 selectMediaResource(); 3457 3460 3458 3461 if (endedPlayback()) … … 3467 3470 m_playbackStartedTime = currentMediaTime().toDouble(); 3468 3471 scheduleEvent(eventNames().playEvent); 3469 3470 if (m_readyState <= HAVE_CURRENT_DATA)3471 scheduleEvent(eventNames().waitingEvent);3472 else if (m_readyState >= HAVE_FUTURE_DATA)3473 scheduleNotifyAboutPlaying();3474 3472 3475 3473 #if ENABLE(MEDIA_SESSION) … … 3493 3491 if (!m_session->invoke()) { 3494 3492 pause(); 3495 return false;3493 return; 3496 3494 } 3497 3495 } 3498 3496 } 3499 3497 #endif 3498 if (m_readyState <= HAVE_CURRENT_DATA) 3499 scheduleEvent(eventNames().waitingEvent); 3500 else if (m_readyState >= HAVE_FUTURE_DATA) 3501 scheduleNotifyAboutPlaying(); 3500 3502 } else if (m_readyState >= HAVE_FUTURE_DATA) 3501 3503 scheduleResolvePendingPlayPromises(); … … 3511 3513 m_autoplaying = false; 3512 3514 updatePlayState(); 3513 3514 return true;3515 3515 } 3516 3516 … … 3546 3546 if (!m_mediaSession->playbackPermitted(*this)) 3547 3547 return; 3548 prepareForLoad();3548 selectMediaResource(); 3549 3549 } 3550 3550 … … 3560 3560 scheduleTimeupdateEvent(false); 3561 3561 scheduleEvent(eventNames().pauseEvent); 3562 m_promiseTaskQueue.enqueueTask([this]() { 3563 rejectPendingPlayPromises(DOMException::create(AbortError)); 3564 }); 3562 scheduleRejectPendingPlayPromises(DOMException::create(AbortError)); 3565 3563 if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) 3566 3564 purgeBufferedDataIfPossible(); … … 5532 5530 m_promiseTaskQueue.close(); 5533 5531 m_updatePlaybackControlsManagerQueue.close(); 5532 m_resourceSelectionTaskQueue.close(); 5534 5533 5535 5534 // Once an active DOM object has been stopped it can not be restarted, so we can deallocate -
trunk/Source/WebCore/html/HTMLMediaElement.h
r225696 r226059 184 184 void scheduleDelayedAction(DelayedActionType); 185 185 void scheduleResolvePendingPlayPromises(); 186 void rejectPendingPlayPromises(DOMException&); 187 void resolvePendingPlayPromises(); 186 void scheduleRejectPendingPlayPromises(Ref<DOMException>&&); 187 using PlayPromiseVector = Vector<DOMPromiseDeferred<void>>; 188 void rejectPendingPlayPromises(PlayPromiseVector&&, Ref<DOMException>&&); 189 void resolvePendingPlayPromises(PlayPromiseVector&&); 188 190 void scheduleNotifyAboutPlaying(); 189 void notifyAboutPlaying( );191 void notifyAboutPlaying(PlayPromiseVector&&); 190 192 191 193 MediaPlayerEnums::MovieLoadType movieLoadType() const; … … 771 773 772 774 // These "internal" functions do not check user gesture restrictions. 773 boolplayInternal();775 void playInternal(); 774 776 void pauseInternal(); 775 777 … … 927 929 GenericEventQueue m_asyncEventQueue; 928 930 929 Vector<DOMPromiseDeferred<void>>m_pendingPlayPromises;931 PlayPromiseVector m_pendingPlayPromises; 930 932 931 933 double m_requestedPlaybackRate { 1 };
Note: See TracChangeset
for help on using the changeset viewer.