0c7c7ab5b626e257032cbd9eb24191229a4c8d2d
[WebKit-https.git] / Source / WebCore / html / HTMLMediaElement.cpp
1 /*
2  * Copyright (C) 2007-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "HTMLMediaElement.h"
28
29 #if ENABLE(VIDEO)
30
31 #include "ApplicationCacheHost.h"
32 #include "ApplicationCacheResource.h"
33 #include "Attribute.h"
34 #include "Blob.h"
35 #include "CSSPropertyNames.h"
36 #include "CSSValueKeywords.h"
37 #include "ChromeClient.h"
38 #include "CommonVM.h"
39 #include "ContentSecurityPolicy.h"
40 #include "ContentType.h"
41 #include "CookieJar.h"
42 #include "DeprecatedGlobalSettings.h"
43 #include "DiagnosticLoggingClient.h"
44 #include "DiagnosticLoggingKeys.h"
45 #include "Document.h"
46 #include "DocumentLoader.h"
47 #include "ElementChildIterator.h"
48 #include "EventNames.h"
49 #include "FrameLoader.h"
50 #include "FrameLoaderClient.h"
51 #include "FrameView.h"
52 #include "HTMLParserIdioms.h"
53 #include "HTMLSourceElement.h"
54 #include "HTMLVideoElement.h"
55 #include "JSDOMException.h"
56 #include "JSDOMPromiseDeferred.h"
57 #include "JSHTMLMediaElement.h"
58 #include "Logging.h"
59 #include "MIMETypeRegistry.h"
60 #include "MainFrame.h"
61 #include "MediaController.h"
62 #include "MediaControls.h"
63 #include "MediaDocument.h"
64 #include "MediaError.h"
65 #include "MediaFragmentURIParser.h"
66 #include "MediaList.h"
67 #include "MediaPlayer.h"
68 #include "MediaQueryEvaluator.h"
69 #include "MediaResourceLoader.h"
70 #include "NetworkingContext.h"
71 #include "NoEventDispatchAssertion.h"
72 #include "Page.h"
73 #include "PageGroup.h"
74 #include "PlatformMediaSessionManager.h"
75 #include "ProgressTracker.h"
76 #include "RenderLayerCompositor.h"
77 #include "RenderTheme.h"
78 #include "RenderVideo.h"
79 #include "RenderView.h"
80 #include "ResourceLoadInfo.h"
81 #include "ScriptController.h"
82 #include "ScriptSourceCode.h"
83 #include "SecurityOriginData.h"
84 #include "SecurityPolicy.h"
85 #include "Settings.h"
86 #include "ShadowRoot.h"
87 #include "TimeRanges.h"
88 #include "UserContentController.h"
89 #include "UserGestureIndicator.h"
90 #include <limits>
91 #include <pal/Logger.h>
92 #include <pal/SessionID.h>
93 #include <pal/system/SleepDisabler.h>
94 #include <runtime/Uint8Array.h>
95 #include <wtf/Algorithms.h>
96 #include <wtf/CurrentTime.h>
97 #include <wtf/Language.h>
98 #include <wtf/MathExtras.h>
99 #include <wtf/MemoryPressureHandler.h>
100 #include <wtf/Ref.h>
101 #include <wtf/text/CString.h>
102
103 #if ENABLE(VIDEO_TRACK)
104 #include "AudioTrackList.h"
105 #include "HTMLTrackElement.h"
106 #include "InbandGenericTextTrack.h"
107 #include "InbandTextTrackPrivate.h"
108 #include "InbandWebVTTTextTrack.h"
109 #include "RuntimeEnabledFeatures.h"
110 #include "TextTrackCueList.h"
111 #include "TextTrackList.h"
112 #include "VideoTrackList.h"
113 #endif
114
115 #if ENABLE(WEB_AUDIO)
116 #include "AudioSourceProvider.h"
117 #include "MediaElementAudioSourceNode.h"
118 #endif
119
120 #if PLATFORM(IOS)
121 #include "RuntimeApplicationChecks.h"
122 #include "VideoFullscreenInterfaceAVKit.h"
123 #endif
124
125 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
126 #include "WebKitPlaybackTargetAvailabilityEvent.h"
127 #endif
128
129 #if ENABLE(MEDIA_SESSION)
130 #include "MediaSession.h"
131 #endif
132
133 #if ENABLE(MEDIA_SOURCE)
134 #include "DOMWindow.h"
135 #include "MediaSource.h"
136 #include "VideoPlaybackQuality.h"
137 #endif
138
139 #if ENABLE(MEDIA_STREAM)
140 #include "DOMURL.h"
141 #include "MediaStream.h"
142 #include "MediaStreamRegistry.h"
143 #endif
144
145 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
146 #include "WebKitMediaKeyNeededEvent.h"
147 #include "WebKitMediaKeys.h"
148 #endif
149
150 #if ENABLE(ENCRYPTED_MEDIA)
151 #include "MediaEncryptedEvent.h"
152 #include "MediaKeys.h"
153 #endif
154
155 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
156 #include "JSMediaControlsHost.h"
157 #include "MediaControlsHost.h"
158 #include <bindings/ScriptObject.h>
159 #endif
160
161 #if ENABLE(ENCRYPTED_MEDIA)
162 #include "NotImplemented.h"
163 #endif
164
165 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
166 #include "VideoFullscreenModel.h"
167 #endif
168
169 namespace PAL {
170 template <>
171 struct LogArgument<WebCore::URL> {
172     static String toString(const WebCore::URL& url)
173     {
174 #if !LOG_DISABLED
175         static const unsigned maximumURLLengthForLogging = 512;
176
177         if (url.string().length() < maximumURLLengthForLogging)
178             return url.string();
179         return url.string().substring(0, maximumURLLengthForLogging) + "...";
180 #else
181         UNUSED_PARAM(url);
182         return "[url]";
183 #endif
184     }
185 };
186 }
187
188
189 namespace WebCore {
190 using namespace PAL;
191
192 static const Seconds SeekRepeatDelay { 100_ms };
193 static const double SeekTime = 0.2;
194 static const Seconds ScanRepeatDelay { 1.5_s };
195 static const double ScanMaximumRate = 8;
196 static const double AutoplayInterferenceTimeThreshold = 10;
197
198 static const Seconds hideMediaControlsAfterEndedDelay { 6_s };
199
200 static void setFlags(unsigned& value, unsigned flags)
201 {
202     value |= flags;
203 }
204
205 static void clearFlags(unsigned& value, unsigned flags)
206 {
207     value &= ~flags;
208 }
209
210 #if !RELEASE_LOG_DISABLED
211 static String actionName(HTMLMediaElementEnums::DelayedActionType action)
212 {
213     StringBuilder actionBuilder;
214
215 #define ACTION(_actionType) \
216     if (action & (HTMLMediaElementEnums::_actionType)) { \
217         if (!actionBuilder.isEmpty()) \
218         actionBuilder.appendLiteral(", "); \
219         actionBuilder.append(#_actionType); \
220     } \
221
222     ACTION(LoadMediaResource);
223     ACTION(ConfigureTextTracks);
224     ACTION(TextTrackChangesNotification);
225     ACTION(ConfigureTextTrackDisplay);
226     ACTION(CheckPlaybackTargetCompatablity);
227     ACTION(CheckMediaState);
228     ACTION(MediaEngineUpdated);
229     ACTION(UpdatePlayState);
230
231 #undef ACTION
232
233     String name = actionBuilder.toString();
234     ASSERT(!name.isEmpty());
235     return name;
236 }
237 #endif
238
239 #ifndef LOG_CACHED_TIME_WARNINGS
240 // Default to not logging warnings about excessive drift in the cached media time because it adds a
241 // fair amount of overhead and logging.
242 #define LOG_CACHED_TIME_WARNINGS 0
243 #endif
244
245 #if ENABLE(MEDIA_SOURCE)
246 // URL protocol used to signal that the media source API is being used.
247 static const char* mediaSourceBlobProtocol = "blob";
248 #endif
249
250 #if ENABLE(MEDIA_STREAM)
251 // URL protocol used to signal that the media stream API is being used.
252 static const char* mediaStreamBlobProtocol = "blob";
253 #endif
254
255 using namespace HTMLNames;
256
257 typedef HashMap<Document*, HashSet<HTMLMediaElement*>> DocumentElementSetMap;
258 static DocumentElementSetMap& documentToElementSetMap()
259 {
260     static NeverDestroyed<DocumentElementSetMap> map;
261     return map;
262 }
263
264 static void addElementToDocumentMap(HTMLMediaElement& element, Document& document)
265 {
266     DocumentElementSetMap& map = documentToElementSetMap();
267     HashSet<HTMLMediaElement*> set = map.take(&document);
268     set.add(&element);
269     map.add(&document, set);
270 }
271
272 static void removeElementFromDocumentMap(HTMLMediaElement& element, Document& document)
273 {
274     DocumentElementSetMap& map = documentToElementSetMap();
275     HashSet<HTMLMediaElement*> set = map.take(&document);
276     set.remove(&element);
277     if (!set.isEmpty())
278         map.add(&document, set);
279 }
280
281 #if ENABLE(VIDEO_TRACK)
282
283 class TrackDisplayUpdateScope {
284 public:
285     TrackDisplayUpdateScope(HTMLMediaElement& element)
286         : m_element(element)
287     {
288         m_element.beginIgnoringTrackDisplayUpdateRequests();
289     }
290     ~TrackDisplayUpdateScope()
291     {
292         m_element.endIgnoringTrackDisplayUpdateRequests();
293     }
294
295 private:
296     HTMLMediaElement& m_element;
297 };
298
299 #endif
300
301 struct HTMLMediaElement::TrackGroup {
302     enum GroupKind { CaptionsAndSubtitles, Description, Chapter, Metadata, Other };
303
304     TrackGroup(GroupKind kind)
305         : kind(kind)
306     {
307     }
308
309     Vector<RefPtr<TextTrack>> tracks;
310     RefPtr<TextTrack> visibleTrack;
311     RefPtr<TextTrack> defaultTrack;
312     GroupKind kind;
313     bool hasSrcLang { false };
314 };
315
316 HashSet<HTMLMediaElement*>& HTMLMediaElement::allMediaElements()
317 {
318     static NeverDestroyed<HashSet<HTMLMediaElement*>> elements;
319     return elements;
320 }
321
322 #if ENABLE(MEDIA_SESSION)
323 typedef HashMap<uint64_t, HTMLMediaElement*> IDToElementMap;
324
325 static IDToElementMap& elementIDsToElements()
326 {
327     static NeverDestroyed<IDToElementMap> map;
328     return map;
329 }
330
331 HTMLMediaElement* HTMLMediaElement::elementWithID(uint64_t id)
332 {
333     if (id == HTMLMediaElementInvalidID)
334         return nullptr;
335
336     return elementIDsToElements().get(id);
337 }
338
339 static uint64_t nextElementID()
340 {
341     static uint64_t elementID = 0;
342     return ++elementID;
343 }
344 #endif
345
346 struct MediaElementSessionInfo {
347     const MediaElementSession* session;
348     MediaElementSession::PlaybackControlsPurpose purpose;
349
350     double timeOfLastUserInteraction;
351     bool canShowControlsManager : 1;
352     bool isVisibleInViewportOrFullscreen : 1;
353     bool isLargeEnoughForMainContent : 1;
354     bool isPlayingAudio : 1;
355 };
356
357 static MediaElementSessionInfo mediaElementSessionInfoForSession(const MediaElementSession& session, MediaElementSession::PlaybackControlsPurpose purpose)
358 {
359     const HTMLMediaElement& element = session.element();
360     return {
361         &session,
362         purpose,
363         session.mostRecentUserInteractionTime(),
364         session.canShowControlsManager(purpose),
365         element.isFullscreen() || element.isVisibleInViewport(),
366         session.isLargeEnoughForMainContent(MediaSessionMainContentPurpose::MediaControls),
367         element.isPlaying() && element.hasAudio() && !element.muted()
368     };
369 }
370
371 static bool preferMediaControlsForCandidateSessionOverOtherCandidateSession(const MediaElementSessionInfo& session, const MediaElementSessionInfo& otherSession)
372 {
373     MediaElementSession::PlaybackControlsPurpose purpose = session.purpose;
374     ASSERT(purpose == otherSession.purpose);
375
376     // For the controls manager, prioritize visible media over offscreen media.
377     if (purpose == MediaElementSession::PlaybackControlsPurpose::ControlsManager && session.isVisibleInViewportOrFullscreen != otherSession.isVisibleInViewportOrFullscreen)
378         return session.isVisibleInViewportOrFullscreen;
379
380     // For Now Playing, prioritize elements that would normally satisfy main content.
381     if (purpose == MediaElementSession::PlaybackControlsPurpose::NowPlaying && session.isLargeEnoughForMainContent != otherSession.isLargeEnoughForMainContent)
382         return session.isLargeEnoughForMainContent;
383
384     // As a tiebreaker, prioritize elements that the user recently interacted with.
385     return session.timeOfLastUserInteraction > otherSession.timeOfLastUserInteraction;
386 }
387
388 static bool mediaSessionMayBeConfusedWithMainContent(const MediaElementSessionInfo& session, MediaElementSession::PlaybackControlsPurpose purpose)
389 {
390     if (purpose == MediaElementSession::PlaybackControlsPurpose::NowPlaying)
391         return session.isPlayingAudio;
392
393     if (!session.isVisibleInViewportOrFullscreen)
394         return false;
395
396     if (!session.isLargeEnoughForMainContent)
397         return false;
398
399     // Even if this video is not a candidate, if it is visible to the user and large enough
400     // to be main content, it poses a risk for being confused with main content.
401     return true;
402 }
403
404 #if !RELEASE_LOG_DISABLED
405 static uint64_t nextLogIdentifier()
406 {
407     static uint64_t logIdentifier = cryptographicallyRandomNumber();
408     return ++logIdentifier;
409 }
410 #endif
411
412 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& document, bool createdByParser)
413     : HTMLElement(tagName, document)
414     , ActiveDOMObject(&document)
415     , m_pendingActionTimer(*this, &HTMLMediaElement::pendingActionTimerFired)
416     , m_progressEventTimer(*this, &HTMLMediaElement::progressEventTimerFired)
417     , m_playbackProgressTimer(*this, &HTMLMediaElement::playbackProgressTimerFired)
418     , m_scanTimer(*this, &HTMLMediaElement::scanTimerFired)
419     , m_playbackControlsManagerBehaviorRestrictionsTimer(*this, &HTMLMediaElement::playbackControlsManagerBehaviorRestrictionsTimerFired)
420     , m_seekToPlaybackPositionEndedTimer(*this, &HTMLMediaElement::seekToPlaybackPositionEndedTimerFired)
421     , m_asyncEventQueue(*this)
422     , m_lastTimeUpdateEventMovieTime(MediaTime::positiveInfiniteTime())
423     , m_firstTimePlaying(true)
424     , m_playing(false)
425     , m_isWaitingUntilMediaCanStart(false)
426     , m_shouldDelayLoadEvent(false)
427     , m_haveFiredLoadedData(false)
428     , m_inActiveDocument(true)
429     , m_autoplaying(true)
430     , m_muted(false)
431     , m_explicitlyMuted(false)
432     , m_initiallyMuted(false)
433     , m_paused(true)
434     , m_seeking(false)
435     , m_seekRequested(false)
436     , m_sentStalledEvent(false)
437     , m_sentEndEvent(false)
438     , m_pausedInternal(false)
439     , m_closedCaptionsVisible(false)
440     , m_webkitLegacyClosedCaptionOverride(false)
441     , m_completelyLoaded(false)
442     , m_havePreparedToPlay(false)
443     , m_parsingInProgress(createdByParser)
444     , m_elementIsHidden(document.hidden())
445     , m_creatingControls(false)
446     , m_receivedLayoutSizeChanged(false)
447     , m_hasEverNotifiedAboutPlaying(false)
448     , m_hasEverHadAudio(false)
449     , m_hasEverHadVideo(false)
450 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
451     , m_mediaControlsDependOnPageScaleFactor(false)
452     , m_haveSetUpCaptionContainer(false)
453 #endif
454     , m_isScrubbingRemotely(false)
455 #if ENABLE(VIDEO_TRACK)
456     , m_tracksAreReady(true)
457     , m_haveVisibleTextTrack(false)
458     , m_processingPreferenceChange(false)
459 #endif
460 #if !RELEASE_LOG_DISABLED
461     , m_logger(&document.logger())
462     , m_logIdentifier(nextLogIdentifier())
463 #endif
464 {
465     allMediaElements().add(this);
466
467     ALWAYS_LOG(LOGIDENTIFIER);
468
469     setHasCustomStyleResolveCallbacks();
470 }
471
472 void HTMLMediaElement::finishInitialization()
473 {
474     m_mediaSession = std::make_unique<MediaElementSession>(*this);
475
476     m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForFullscreen);
477     m_mediaSession->addBehaviorRestriction(MediaElementSession::RequirePageConsentToLoadMedia);
478 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
479     m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureToAutoplayToExternalDevice);
480 #endif
481     m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureToControlControlsManager);
482     m_mediaSession->addBehaviorRestriction(MediaElementSession::RequirePlaybackToControlControlsManager);
483
484     auto& document = this->document();
485     auto* page = document.page();
486
487     if (document.settings().invisibleAutoplayNotPermitted())
488         m_mediaSession->addBehaviorRestriction(MediaElementSession::InvisibleAutoplayNotPermitted);
489
490     if (document.ownerElement() || !document.isMediaDocument()) {
491         const auto& topDocument = document.topDocument();
492         const bool isProcessingUserGesture = processingUserGestureForMedia();
493         const bool shouldAudioPlaybackRequireUserGesture = topDocument.audioPlaybackRequiresUserGesture() && !isProcessingUserGesture;
494         const bool shouldVideoPlaybackRequireUserGesture = topDocument.videoPlaybackRequiresUserGesture() && !isProcessingUserGesture;
495
496         if (shouldVideoPlaybackRequireUserGesture) {
497             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForVideoRateChange);
498             if (document.settings().requiresUserGestureToLoadVideo())
499                 m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForLoad);
500         }
501
502         if (page && page->isLowPowerModeEnabled())
503             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForVideoDueToLowPowerMode);
504
505         if (shouldAudioPlaybackRequireUserGesture)
506             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForAudioRateChange);
507
508 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
509         if (shouldVideoPlaybackRequireUserGesture || shouldAudioPlaybackRequireUserGesture)
510             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureToShowPlaybackTargetPicker);
511 #endif
512
513         if (!document.settings().mediaDataLoadsAutomatically())
514             m_mediaSession->addBehaviorRestriction(MediaElementSession::AutoPreloadingNotPermitted);
515
516         if (document.settings().mainContentUserGestureOverrideEnabled())
517             m_mediaSession->addBehaviorRestriction(MediaElementSession::OverrideUserGestureRequirementForMainContent);
518     }
519
520 #if PLATFORM(IOS)
521     if (!document.settings().videoPlaybackRequiresUserGesture() && !document.settings().audioPlaybackRequiresUserGesture()) {
522         // Relax RequireUserGestureForFullscreen when videoPlaybackRequiresUserGesture and audioPlaybackRequiresUserGesture is not set:
523         m_mediaSession->removeBehaviorRestriction(MediaElementSession::RequireUserGestureForFullscreen);
524     }
525 #endif
526
527 #if ENABLE(VIDEO_TRACK)
528     if (page)
529         m_captionDisplayMode = page->group().captionPreferences().captionDisplayMode();
530 #endif
531
532 #if ENABLE(MEDIA_SESSION)
533     m_elementID = nextElementID();
534     elementIDsToElements().add(m_elementID, this);
535
536     setSessionInternal(document.defaultMediaSession());
537 #endif
538
539     registerWithDocument(document);
540
541 #if USE(AUDIO_SESSION) && PLATFORM(MAC)
542     AudioSession::sharedSession().addMutedStateObserver(this);
543 #endif
544
545     mediaSession().clientWillBeginAutoplaying();
546 }
547
548 HTMLMediaElement::~HTMLMediaElement()
549 {
550     ALWAYS_LOG(LOGIDENTIFIER);
551
552     beginIgnoringTrackDisplayUpdateRequests();
553     allMediaElements().remove(this);
554
555     m_asyncEventQueue.close();
556
557     setShouldDelayLoadEvent(false);
558     unregisterWithDocument(document());
559
560 #if USE(AUDIO_SESSION) && PLATFORM(MAC)
561     AudioSession::sharedSession().removeMutedStateObserver(this);
562 #endif
563
564 #if ENABLE(VIDEO_TRACK)
565     if (m_audioTracks)
566         m_audioTracks->clearElement();
567     if (m_textTracks)
568         m_textTracks->clearElement();
569     if (m_videoTracks)
570         m_videoTracks->clearElement();
571 #endif
572
573 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
574     if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent)) {
575         m_hasPlaybackTargetAvailabilityListeners = false;
576         m_mediaSession->setHasPlaybackTargetAvailabilityListeners(*this, false);
577         updateMediaState();
578     }
579 #endif
580
581     if (m_mediaController) {
582         m_mediaController->removeMediaElement(*this);
583         m_mediaController = nullptr;
584     }
585
586 #if ENABLE(MEDIA_SOURCE)
587     detachMediaSource();
588 #endif
589
590 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
591     webkitSetMediaKeys(nullptr);
592 #endif
593
594 #if ENABLE(ENCRYPTED_MEDIA)
595     if (m_mediaKeys) {
596         m_mediaKeys->detachCDMClient(*this);
597         if (m_player)
598             m_player->cdmInstanceDetached(m_mediaKeys->cdmInstance());
599     }
600 #endif
601
602 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
603     if (m_isolatedWorld)
604         m_isolatedWorld->clearWrappers();
605 #endif
606
607 #if ENABLE(MEDIA_SESSION)
608     if (m_session) {
609         m_session->removeMediaElement(*this);
610         m_session = nullptr;
611     }
612
613     elementIDsToElements().remove(m_elementID);
614 #endif
615
616     m_seekTaskQueue.close();
617     m_promiseTaskQueue.close();
618     m_pauseAfterDetachedTaskQueue.close();
619     m_updatePlaybackControlsManagerQueue.close();
620     m_playbackControlsManagerBehaviorRestrictionsQueue.close();
621     m_resourceSelectionTaskQueue.close();
622     m_visibilityChangeTaskQueue.close();
623 #if ENABLE(ENCRYPTED_MEDIA)
624     m_encryptedMediaQueue.close();
625 #endif
626
627     m_completelyLoaded = true;
628
629     if (m_player) {
630         m_player->invalidate();
631         m_player = nullptr;
632     }
633
634     m_mediaSession = nullptr;
635     updatePlaybackControlsManager();
636 }
637
638 static bool needsAutoplayPlayPauseEventsQuirk(const Document& document)
639 {
640     auto* page = document.page();
641     if (!page || !page->settings().needsSiteSpecificQuirks())
642         return false;
643
644     auto* loader = document.loader();
645     return loader && loader->allowedAutoplayQuirks().contains(AutoplayQuirk::SynthesizedPauseEvents);
646 }
647
648 HTMLMediaElement* HTMLMediaElement::bestMediaElementForShowingPlaybackControlsManager(MediaElementSession::PlaybackControlsPurpose purpose)
649 {
650     auto allSessions = PlatformMediaSessionManager::sharedManager().currentSessionsMatching([] (const PlatformMediaSession& session) {
651         return is<MediaElementSession>(session);
652     });
653
654     Vector<MediaElementSessionInfo> candidateSessions;
655     bool atLeastOneNonCandidateMayBeConfusedForMainContent = false;
656     for (auto& session : allSessions) {
657         auto mediaElementSessionInfo = mediaElementSessionInfoForSession(downcast<MediaElementSession>(*session), purpose);
658         if (mediaElementSessionInfo.canShowControlsManager)
659             candidateSessions.append(mediaElementSessionInfo);
660         else if (mediaSessionMayBeConfusedWithMainContent(mediaElementSessionInfo, purpose))
661             atLeastOneNonCandidateMayBeConfusedForMainContent = true;
662     }
663
664     if (!candidateSessions.size())
665         return nullptr;
666
667     std::sort(candidateSessions.begin(), candidateSessions.end(), preferMediaControlsForCandidateSessionOverOtherCandidateSession);
668     auto strongestSessionCandidate = candidateSessions.first();
669     if (!strongestSessionCandidate.isVisibleInViewportOrFullscreen && !strongestSessionCandidate.isPlayingAudio && atLeastOneNonCandidateMayBeConfusedForMainContent)
670         return nullptr;
671
672     return &strongestSessionCandidate.session->element();
673 }
674
675 void HTMLMediaElement::registerWithDocument(Document& document)
676 {
677     m_mediaSession->registerWithDocument(document);
678
679     if (m_isWaitingUntilMediaCanStart)
680         document.addMediaCanStartListener(this);
681
682 #if !PLATFORM(IOS)
683     document.registerForMediaVolumeCallbacks(this);
684     document.registerForPrivateBrowsingStateChangedCallbacks(this);
685 #endif
686
687     document.registerForVisibilityStateChangedCallbacks(this);
688
689 #if ENABLE(VIDEO_TRACK)
690     if (m_requireCaptionPreferencesChangedCallbacks)
691         document.registerForCaptionPreferencesChangedCallbacks(this);
692 #endif
693
694 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
695     if (m_mediaControlsDependOnPageScaleFactor)
696         document.registerForPageScaleFactorChangedCallbacks(this);
697     document.registerForUserInterfaceLayoutDirectionChangedCallbacks(*this);
698 #endif
699
700 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
701     document.registerForDocumentSuspensionCallbacks(this);
702 #endif
703
704     document.registerForAllowsMediaDocumentInlinePlaybackChangedCallbacks(*this);
705
706     document.addAudioProducer(this);
707     addElementToDocumentMap(*this, document);
708
709 #if ENABLE(MEDIA_STREAM)
710     document.registerForMediaStreamStateChangeCallbacks(*this);
711 #endif
712 }
713
714 void HTMLMediaElement::unregisterWithDocument(Document& document)
715 {
716     m_mediaSession->unregisterWithDocument(document);
717
718     if (m_isWaitingUntilMediaCanStart)
719         document.removeMediaCanStartListener(this);
720
721 #if !PLATFORM(IOS)
722     document.unregisterForMediaVolumeCallbacks(this);
723     document.unregisterForPrivateBrowsingStateChangedCallbacks(this);
724 #endif
725
726     document.unregisterForVisibilityStateChangedCallbacks(this);
727
728 #if ENABLE(VIDEO_TRACK)
729     if (m_requireCaptionPreferencesChangedCallbacks)
730         document.unregisterForCaptionPreferencesChangedCallbacks(this);
731 #endif
732
733 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
734     if (m_mediaControlsDependOnPageScaleFactor)
735         document.unregisterForPageScaleFactorChangedCallbacks(this);
736     document.unregisterForUserInterfaceLayoutDirectionChangedCallbacks(*this);
737 #endif
738
739 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
740     document.unregisterForDocumentSuspensionCallbacks(this);
741 #endif
742
743     document.unregisterForAllowsMediaDocumentInlinePlaybackChangedCallbacks(*this);
744
745     document.removeAudioProducer(this);
746     removeElementFromDocumentMap(*this, document);
747
748 #if ENABLE(MEDIA_STREAM)
749     document.unregisterForMediaStreamStateChangeCallbacks(*this);
750 #endif
751
752 }
753
754 void HTMLMediaElement::didMoveToNewDocument(Document& oldDocument, Document& newDocument)
755 {
756     ASSERT_WITH_SECURITY_IMPLICATION(&document() == &newDocument);
757     if (m_shouldDelayLoadEvent) {
758         oldDocument.decrementLoadEventDelayCount();
759         newDocument.incrementLoadEventDelayCount();
760     }
761
762     unregisterWithDocument(oldDocument);
763     registerWithDocument(newDocument);
764
765     HTMLElement::didMoveToNewDocument(oldDocument, newDocument);
766     updateShouldAutoplay();
767 }
768
769 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
770 void HTMLMediaElement::prepareForDocumentSuspension()
771 {
772     m_mediaSession->unregisterWithDocument(document());
773 }
774
775 void HTMLMediaElement::resumeFromDocumentSuspension()
776 {
777     m_mediaSession->registerWithDocument(document());
778     updateShouldAutoplay();
779 }
780 #endif
781
782 bool HTMLMediaElement::supportsFocus() const
783 {
784     if (document().isMediaDocument())
785         return false;
786
787     // If no controls specified, we should still be able to focus the element if it has tabIndex.
788     return controls() ||  HTMLElement::supportsFocus();
789 }
790
791 bool HTMLMediaElement::isMouseFocusable() const
792 {
793     return false;
794 }
795
796 void HTMLMediaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
797 {
798     if (name == srcAttr) {
799         // https://html.spec.whatwg.org/multipage/embedded-content.html#location-of-the-media-resource
800         // Location of the Media Resource
801         // 12 February 2017
802
803         // If a src attribute of a media element is set or changed, the user
804         // agent must invoke the media element's media element load algorithm.
805 #if PLATFORM(IOS)
806         // Note, unless the restriction on requiring user action has been removed,
807         // do not begin downloading data on iOS.
808         if (!value.isNull() && m_mediaSession->dataLoadingPermitted(*this))
809 #else
810         if (!value.isNull())
811 #endif
812             prepareForLoad();
813     } else if (name == controlsAttr)
814         configureMediaControls();
815     else if (name == loopAttr)
816         updateSleepDisabling();
817     else if (name == preloadAttr) {
818         if (equalLettersIgnoringASCIICase(value, "none"))
819             m_preload = MediaPlayer::None;
820         else if (equalLettersIgnoringASCIICase(value, "metadata"))
821             m_preload = MediaPlayer::MetaData;
822         else {
823             // The spec does not define an "invalid value default" but "auto" is suggested as the
824             // "missing value default", so use it for everything except "none" and "metadata"
825             m_preload = MediaPlayer::Auto;
826         }
827
828         // The attribute must be ignored if the autoplay attribute is present
829         if (!autoplay() && !m_havePreparedToPlay && m_player)
830             m_player->setPreload(m_mediaSession->effectivePreloadForElement(*this));
831
832     } else if (name == mediagroupAttr)
833         setMediaGroup(value);
834     else if (name == autoplayAttr) {
835         if (processingUserGestureForMedia())
836             removeBehaviorsRestrictionsAfterFirstUserGesture();
837     }
838     else
839         HTMLElement::parseAttribute(name, value);
840 }
841
842 void HTMLMediaElement::finishParsingChildren()
843 {
844     HTMLElement::finishParsingChildren();
845     m_parsingInProgress = false;
846
847 #if ENABLE(VIDEO_TRACK)
848     if (childrenOfType<HTMLTrackElement>(*this).first())
849         scheduleDelayedAction(ConfigureTextTracks);
850 #endif
851 }
852
853 bool HTMLMediaElement::rendererIsNeeded(const RenderStyle& style)
854 {
855     return controls() && HTMLElement::rendererIsNeeded(style);
856 }
857
858 RenderPtr<RenderElement> HTMLMediaElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
859 {
860     return createRenderer<RenderMedia>(*this, WTFMove(style));
861 }
862
863 bool HTMLMediaElement::childShouldCreateRenderer(const Node& child) const
864 {
865 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
866     return hasShadowRootParent(child) && HTMLElement::childShouldCreateRenderer(child);
867 #else
868     if (!hasMediaControls())
869         return false;
870     // <media> doesn't allow its content, including shadow subtree, to
871     // be rendered. So this should return false for most of the children.
872     // One exception is a shadow tree built for rendering controls which should be visible.
873     // So we let them go here by comparing its subtree root with one of the controls.
874     return &mediaControls()->treeScope() == &child.treeScope()
875         && hasShadowRootParent(child)
876         && HTMLElement::childShouldCreateRenderer(child);
877 #endif
878 }
879
880 Node::InsertedIntoAncestorResult HTMLMediaElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
881 {
882     INFO_LOG(LOGIDENTIFIER);
883
884     HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
885     if (insertionType.connectedToDocument) {
886         m_inActiveDocument = true;
887
888 #if PLATFORM(IOS)
889         if (m_networkState == NETWORK_EMPTY && !attributeWithoutSynchronization(srcAttr).isEmpty() && m_mediaSession->dataLoadingPermitted(*this))
890 #else
891         if (m_networkState == NETWORK_EMPTY && !attributeWithoutSynchronization(srcAttr).isEmpty())
892 #endif
893             prepareForLoad();
894     }
895
896     if (!m_explicitlyMuted) {
897         m_explicitlyMuted = true;
898         m_muted = hasAttributeWithoutSynchronization(mutedAttr);
899         m_mediaSession->canProduceAudioChanged();
900     }
901
902     return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
903 }
904
905 void HTMLMediaElement::didFinishInsertingNode()
906 {
907     configureMediaControls();
908 }
909
910 void HTMLMediaElement::pauseAfterDetachedTask()
911 {
912     // If we were re-inserted into an active document, no need to pause.
913     if (m_inActiveDocument)
914         return;
915
916     if (hasMediaControls())
917         mediaControls()->hide();
918     if (m_networkState > NETWORK_EMPTY)
919         pause();
920     if (m_videoFullscreenMode != VideoFullscreenModeNone)
921         exitFullscreen();
922
923     if (!m_player)
924         return;
925
926     size_t extraMemoryCost = m_player->extraMemoryCost();
927     if (extraMemoryCost > m_reportedExtraMemoryCost) {
928         JSC::VM& vm = commonVM();
929         JSC::JSLockHolder lock(vm);
930
931         size_t extraMemoryCostDelta = extraMemoryCost - m_reportedExtraMemoryCost;
932         m_reportedExtraMemoryCost = extraMemoryCost;
933         // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated.
934         // https://bugs.webkit.org/show_bug.cgi?id=142595
935         vm.heap.deprecatedReportExtraMemory(extraMemoryCostDelta);
936     }
937 }
938
939 void HTMLMediaElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
940 {
941     INFO_LOG(LOGIDENTIFIER);
942
943     m_inActiveDocument = false;
944     if (removalType.disconnectedFromDocument) {
945         // Pause asynchronously to let the operation that removed us finish, in case we get inserted back into a document.
946         m_pauseAfterDetachedTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::pauseAfterDetachedTask, this));
947     }
948
949     HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
950 }
951
952 void HTMLMediaElement::willAttachRenderers()
953 {
954     ASSERT(!renderer());
955 }
956
957 inline void HTMLMediaElement::updateRenderer()
958 {
959     if (auto* renderer = this->renderer())
960         renderer->updateFromElement();
961 }
962
963 void HTMLMediaElement::didAttachRenderers()
964 {
965     if (auto* renderer = this->renderer()) {
966         renderer->updateFromElement();
967         if (m_mediaSession && m_mediaSession->wantsToObserveViewportVisibilityForAutoplay())
968             renderer->registerForVisibleInViewportCallback();
969     }
970     updateShouldAutoplay();
971 }
972
973 void HTMLMediaElement::willDetachRenderers()
974 {
975     if (auto* renderer = this->renderer())
976         renderer->unregisterForVisibleInViewportCallback();
977 }
978
979 void HTMLMediaElement::didDetachRenderers()
980 {
981     updateShouldAutoplay();
982 }
983
984 void HTMLMediaElement::didRecalcStyle(Style::Change)
985 {
986     updateRenderer();
987 }
988
989 void HTMLMediaElement::scheduleDelayedAction(DelayedActionType actionType)
990 {
991     if (actionType ^ m_pendingActionFlags)
992         ALWAYS_LOG(LOGIDENTIFIER, "setting ", actionName(actionType), " flag");
993
994 #if ENABLE(VIDEO_TRACK)
995     if (actionType & ConfigureTextTracks)
996         setFlags(m_pendingActionFlags, ConfigureTextTracks);
997 #endif
998
999 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1000     if (actionType & CheckPlaybackTargetCompatablity)
1001         setFlags(m_pendingActionFlags, CheckPlaybackTargetCompatablity);
1002 #endif
1003
1004     if (actionType & CheckMediaState)
1005         setFlags(m_pendingActionFlags, CheckMediaState);
1006
1007     if (actionType & MediaEngineUpdated)
1008         setFlags(m_pendingActionFlags, MediaEngineUpdated);
1009
1010     if (actionType & UpdatePlayState)
1011         setFlags(m_pendingActionFlags, UpdatePlayState);
1012
1013     m_pendingActionTimer.startOneShot(0_s);
1014 }
1015
1016 void HTMLMediaElement::scheduleNextSourceChild()
1017 {
1018     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
1019     m_resourceSelectionTaskQueue.enqueueTask([this] {
1020         loadNextSourceChild();
1021     });
1022 }
1023
1024 void HTMLMediaElement::mediaPlayerActiveSourceBuffersChanged(const MediaPlayer*)
1025 {
1026     m_hasEverHadAudio |= hasAudio();
1027     m_hasEverHadVideo |= hasVideo();
1028 }
1029
1030 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
1031 {
1032     RefPtr<Event> event = Event::create(eventName, false, true);
1033
1034     // Don't set the event target, the event queue will set it in GenericEventQueue::timerFired and setting it here
1035     // will trigger an ASSERT if this element has been marked for deletion.
1036
1037     m_asyncEventQueue.enqueueEvent(WTFMove(event));
1038 }
1039
1040 void HTMLMediaElement::scheduleResolvePendingPlayPromises()
1041 {
1042     m_promiseTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::resolvePendingPlayPromises, this));
1043 }
1044
1045 void HTMLMediaElement::rejectPendingPlayPromises(DOMException& error)
1046 {
1047     Vector<DOMPromiseDeferred<void>> pendingPlayPromises = WTFMove(m_pendingPlayPromises);
1048
1049     for (auto& promise : pendingPlayPromises)
1050         promise.rejectType<IDLInterface<DOMException>>(error);
1051 }
1052
1053 void HTMLMediaElement::resolvePendingPlayPromises()
1054 {
1055     Vector<DOMPromiseDeferred<void>> pendingPlayPromises = WTFMove(m_pendingPlayPromises);
1056
1057     for (auto& promise : pendingPlayPromises)
1058         promise.resolve();
1059 }
1060
1061 void HTMLMediaElement::scheduleNotifyAboutPlaying()
1062 {
1063     m_promiseTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::notifyAboutPlaying, this));
1064 }
1065
1066 void HTMLMediaElement::notifyAboutPlaying()
1067 {
1068     Ref<HTMLMediaElement> protectedThis(*this); // The 'playing' event can make arbitrary DOM mutations.
1069     m_playbackStartedTime = currentMediaTime().toDouble();
1070     dispatchEvent(Event::create(eventNames().playingEvent, false, true));
1071     resolvePendingPlayPromises();
1072
1073     m_hasEverNotifiedAboutPlaying = true;
1074     scheduleUpdatePlaybackControlsManager();
1075 }
1076
1077 bool HTMLMediaElement::hasEverNotifiedAboutPlaying() const
1078 {
1079     return m_hasEverNotifiedAboutPlaying;
1080 }
1081
1082 void HTMLMediaElement::pendingActionTimerFired()
1083 {
1084     Ref<HTMLMediaElement> protectedThis(*this); // loadNextSourceChild may fire 'beforeload', which can make arbitrary DOM mutations.
1085     PendingActionFlags pendingActions = m_pendingActionFlags;
1086     m_pendingActionFlags = 0;
1087
1088     if (!pendingActions)
1089         return;
1090
1091     ALWAYS_LOG(LOGIDENTIFIER, "setting ", actionName(static_cast<DelayedActionType>(pendingActions)), " flag");
1092
1093 #if ENABLE(VIDEO_TRACK)
1094     if (pendingActions & ConfigureTextTracks)
1095         configureTextTracks();
1096 #endif
1097
1098 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1099     if (pendingActions & CheckPlaybackTargetCompatablity && m_isPlayingToWirelessTarget && !m_player->canPlayToWirelessPlaybackTarget()) {
1100         INFO_LOG(LOGIDENTIFIER, "calling setShouldPlayToPlaybackTarget(false)");
1101         m_failedToPlayToWirelessTarget = true;
1102         m_player->setShouldPlayToPlaybackTarget(false);
1103     }
1104
1105     if (pendingActions & CheckMediaState)
1106         updateMediaState();
1107 #endif
1108
1109     if (pendingActions & MediaEngineUpdated)
1110         mediaEngineWasUpdated();
1111
1112     if (pendingActions & UpdatePlayState)
1113         updatePlayState();
1114 }
1115
1116 MediaError* HTMLMediaElement::error() const
1117 {
1118     return m_error.get();
1119 }
1120
1121 void HTMLMediaElement::setSrcObject(MediaProvider&& mediaProvider)
1122 {
1123     // FIXME: Setting the srcObject attribute may cause other changes to the media element's internal state:
1124     // Specifically, if srcObject is specified, the UA must use it as the source of media, even if the src
1125     // attribute is also set or children are present. If the value of srcObject is replaced or set to null
1126     // the UA must re-run the media element load algorithm.
1127     //
1128     // https://bugs.webkit.org/show_bug.cgi?id=124896
1129
1130
1131     // https://www.w3.org/TR/html51/semantics-embedded-content.html#dom-htmlmediaelement-srcobject
1132     // 4.7.14.2. Location of the media resource
1133     // srcObject: On setting, it must set the element’s assigned media provider object to the new
1134     // value, and then invoke the element’s media element load algorithm.
1135     m_mediaProvider = WTFMove(mediaProvider);
1136     prepareForLoad();
1137 }
1138
1139 void HTMLMediaElement::setCrossOrigin(const AtomicString& value)
1140 {
1141     setAttributeWithoutSynchronization(crossoriginAttr, value);
1142 }
1143
1144 String HTMLMediaElement::crossOrigin() const
1145 {
1146     return parseCORSSettingsAttribute(attributeWithoutSynchronization(crossoriginAttr));
1147 }
1148
1149 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
1150 {
1151     return m_networkState;
1152 }
1153
1154 String HTMLMediaElement::canPlayType(const String& mimeType) const
1155 {
1156     MediaEngineSupportParameters parameters;
1157     ContentType contentType(mimeType);
1158     parameters.type = contentType;
1159     parameters.contentTypesRequiringHardwareSupport = mediaContentTypesRequiringHardwareSupport();
1160     MediaPlayer::SupportsType support = MediaPlayer::supportsType(parameters, this);
1161     String canPlay;
1162
1163     // 4.8.10.3
1164     switch (support)
1165     {
1166         case MediaPlayer::IsNotSupported:
1167             canPlay = emptyString();
1168             break;
1169         case MediaPlayer::MayBeSupported:
1170             canPlay = ASCIILiteral("maybe");
1171             break;
1172         case MediaPlayer::IsSupported:
1173             canPlay = ASCIILiteral("probably");
1174             break;
1175     }
1176
1177     DEBUG_LOG(LOGIDENTIFIER, "[", mimeType, "] -> ", canPlay);
1178
1179     return canPlay;
1180 }
1181
1182 double HTMLMediaElement::getStartDate() const
1183 {
1184     if (!m_player)
1185         return std::numeric_limits<double>::quiet_NaN();
1186     return m_player->getStartDate().toDouble();
1187 }
1188
1189 void HTMLMediaElement::load()
1190 {
1191     Ref<HTMLMediaElement> protectedThis(*this); // prepareForLoad may result in a 'beforeload' event, which can make arbitrary DOM mutations.
1192
1193     INFO_LOG(LOGIDENTIFIER);
1194
1195     if (!m_mediaSession->dataLoadingPermitted(*this))
1196         return;
1197     if (processingUserGestureForMedia())
1198         removeBehaviorsRestrictionsAfterFirstUserGesture();
1199
1200     prepareForLoad();
1201     m_resourceSelectionTaskQueue.enqueueTask([this] {
1202         prepareToPlay();
1203     });
1204 }
1205
1206 void HTMLMediaElement::prepareForLoad()
1207 {
1208     // https://html.spec.whatwg.org/multipage/embedded-content.html#media-element-load-algorithm
1209     // The Media Element Load Algorithm
1210     // 12 February 2017
1211
1212     INFO_LOG(LOGIDENTIFIER);
1213
1214     // 1 - Abort any already-running instance of the resource selection algorithm for this element.
1215     // Perform the cleanup required for the resource load algorithm to run.
1216     stopPeriodicTimers();
1217     m_pendingActionTimer.stop();
1218     m_resourceSelectionTaskQueue.cancelAllTasks();
1219     // FIXME: Figure out appropriate place to reset LoadTextTrackResource if necessary and set m_pendingActionFlags to 0 here.
1220     m_sentEndEvent = false;
1221     m_sentStalledEvent = false;
1222     m_haveFiredLoadedData = false;
1223     m_completelyLoaded = false;
1224     m_havePreparedToPlay = false;
1225     m_displayMode = Unknown;
1226     m_currentSrc = URL();
1227
1228 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1229     m_failedToPlayToWirelessTarget = false;
1230 #endif
1231
1232     m_loadState = WaitingForSource;
1233     m_currentSourceNode = nullptr;
1234
1235     createMediaPlayer();
1236
1237     // 2 - Let pending tasks be a list of all tasks from the media element's media element event task source in one of the task queues.
1238     // 3 - For each task in pending tasks that would resolve pending play promises or reject pending play promises, immediately resolve or reject those promises in the order the corresponding tasks were queued.
1239     // 4 - Remove each task in pending tasks from its task queue
1240     cancelPendingEventsAndCallbacks();
1241
1242     // 5 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
1243     // a task to fire a simple event named abort at the media element.
1244     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
1245         scheduleEvent(eventNames().abortEvent);
1246
1247     // 6 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
1248     if (m_networkState != NETWORK_EMPTY) {
1249         // 6.1 - Queue a task to fire a simple event named emptied at the media element.
1250         scheduleEvent(eventNames().emptiedEvent);
1251
1252         // 6.2 - If a fetching process is in progress for the media element, the user agent should stop it.
1253         m_networkState = NETWORK_EMPTY;
1254
1255         // 6.3 - If the media element’s assigned media provider object is a MediaSource object, then detach it.
1256 #if ENABLE(MEDIA_SOURCE)
1257         detachMediaSource();
1258 #endif
1259
1260         // 6.4 - Forget the media element's media-resource-specific tracks.
1261         forgetResourceSpecificTracks();
1262
1263         // 6.5 - If readyState is not set to HAVE_NOTHING, then set it to that state.
1264         m_readyState = HAVE_NOTHING;
1265         m_readyStateMaximum = HAVE_NOTHING;
1266
1267         // 6.6 - If the paused attribute is false, then set it to true.
1268         m_paused = true;
1269
1270         // 6.7 - If seeking is true, set it to false.
1271         clearSeeking();
1272
1273         // 6.8 - Set the current playback position to 0.
1274         //       Set the official playback position to 0.
1275         //       If this changed the official playback position, then queue a task to fire a simple event named timeupdate at the media element.
1276         m_lastSeekTime = MediaTime::zeroTime();
1277         m_playedTimeRanges = TimeRanges::create();
1278         // FIXME: Add support for firing this event. e.g., scheduleEvent(eventNames().timeUpdateEvent);
1279
1280         // 4.9 - Set the initial playback position to 0.
1281         // FIXME: Make this less subtle. The position only becomes 0 because of the createMediaPlayer() call
1282         // above.
1283         refreshCachedTime();
1284
1285         invalidateCachedTime();
1286
1287         // 4.10 - Set the timeline offset to Not-a-Number (NaN).
1288         // 4.11 - Update the duration attribute to Not-a-Number (NaN).
1289
1290         updateMediaController();
1291 #if ENABLE(VIDEO_TRACK)
1292         updateActiveTextTrackCues(MediaTime::zeroTime());
1293 #endif
1294     }
1295
1296     // 7 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
1297     setPlaybackRate(defaultPlaybackRate());
1298
1299     // 8 - Set the error attribute to null and the autoplaying flag to true.
1300     m_error = nullptr;
1301     m_autoplaying = true;
1302     mediaSession().clientWillBeginAutoplaying();
1303
1304     // 9 - Invoke the media element's resource selection algorithm.
1305     selectMediaResource();
1306
1307     // 10 - Note: Playback of any previously playing media resource for this element stops.
1308
1309     configureMediaControls();
1310 }
1311
1312 void HTMLMediaElement::selectMediaResource()
1313 {
1314     // https://www.w3.org/TR/2016/REC-html51-20161101/semantics-embedded-content.html#resource-selection-algorithm
1315     // The Resource Selection Algorithm
1316
1317     // 1. Set the element’s networkState attribute to the NETWORK_NO_SOURCE value.
1318     m_networkState = NETWORK_NO_SOURCE;
1319
1320     // 2. Set the element’s show poster flag to true.
1321     setDisplayMode(Poster);
1322
1323     // 3. Set the media element’s delaying-the-load-event flag to true (this delays the load event).
1324     setShouldDelayLoadEvent(true);
1325
1326     // 4. in parallel await a stable state, allowing the task that invoked this algorithm to continue.
1327     if (m_resourceSelectionTaskQueue.hasPendingTasks())
1328         return;
1329
1330     if (!m_mediaSession->pageAllowsDataLoading(*this)) {
1331         ALWAYS_LOG(LOGIDENTIFIER, "not allowed to load in background, waiting");
1332         setShouldDelayLoadEvent(false);
1333         if (m_isWaitingUntilMediaCanStart)
1334             return;
1335         m_isWaitingUntilMediaCanStart = true;
1336         document().addMediaCanStartListener(this);
1337         return;
1338     }
1339
1340     // Once the page has allowed an element to load media, it is free to load at will. This allows a
1341     // playlist that starts in a foreground tab to continue automatically if the tab is subsequently
1342     // put into the background.
1343     m_mediaSession->removeBehaviorRestriction(MediaElementSession::RequirePageConsentToLoadMedia);
1344
1345
1346     m_resourceSelectionTaskQueue.enqueueTask([this]  {
1347         // 5. If the media element’s blocked-on-parser flag is false, then populate the list of pending text tracks.
1348 #if ENABLE(VIDEO_TRACK)
1349         if (hasMediaControls())
1350             mediaControls()->changedClosedCaptionsVisibility();
1351
1352         // HTMLMediaElement::textTracksAreReady will need "... the text tracks whose mode was not in the
1353         // disabled state when the element's resource selection algorithm last started".
1354         // FIXME: Update this to match "populate the list of pending text tracks" step.
1355         m_textTracksWhenResourceSelectionBegan.clear();
1356         if (m_textTracks) {
1357             for (unsigned i = 0; i < m_textTracks->length(); ++i) {
1358                 RefPtr<TextTrack> track = m_textTracks->item(i);
1359                 if (track->mode() != TextTrack::Mode::Disabled)
1360                     m_textTracksWhenResourceSelectionBegan.append(track);
1361             }
1362         }
1363 #endif
1364
1365         enum Mode { None, Object, Attribute, Children };
1366         Mode mode = None;
1367
1368         if (m_mediaProvider) {
1369             // 6. If the media element has an assigned media provider object, then let mode be object.
1370             mode = Object;
1371         } else if (hasAttributeWithoutSynchronization(srcAttr)) {
1372             //    Otherwise, if the media element has no assigned media provider object but has a src attribute, then let mode be attribute.
1373             mode = Attribute;
1374             ASSERT(m_player);
1375             if (!m_player) {
1376                 ERROR_LOG(LOGIDENTIFIER, " - has srcAttr but m_player is not created");
1377                 return;
1378             }
1379         } else if (auto firstSource = childrenOfType<HTMLSourceElement>(*this).first()) {
1380             //    Otherwise, if the media element does not have an assigned media provider object and does not have a src attribute,
1381             //    but does have a source element child, then let mode be children and let candidate be the first such source element
1382             //    child in tree order.
1383             mode = Children;
1384             m_nextChildNodeToConsider = firstSource;
1385             m_currentSourceNode = nullptr;
1386         } else {
1387             //  Otherwise the media element has no assigned media provider object and has neither a src attribute nor a source
1388             //  element child: set the networkState to NETWORK_EMPTY, and abort these steps; the synchronous section ends.
1389             m_loadState = WaitingForSource;
1390             setShouldDelayLoadEvent(false);
1391             m_networkState = NETWORK_EMPTY;
1392
1393             ALWAYS_LOG(LOGIDENTIFIER, "nothing to load");
1394             return;
1395         }
1396
1397         // 7. Set the media element’s networkState to NETWORK_LOADING.
1398         m_networkState = NETWORK_LOADING;
1399
1400         // 8. Queue a task to fire a simple event named loadstart at the media element.
1401         scheduleEvent(eventNames().loadstartEvent);
1402
1403         // 9. Run the appropriate steps from the following list:
1404         // ↳ If mode is object
1405         if (mode == Object) {
1406             // 1. Set the currentSrc attribute to the empty string.
1407             m_currentSrc = URL();
1408
1409             // 2. End the synchronous section, continuing the remaining steps in parallel.
1410             // 3. Run the resource fetch algorithm with the assigned media provider object.
1411             WTF::visit(WTF::makeVisitor(
1412 #if ENABLE(MEDIA_STREAM)
1413                 [this](RefPtr<MediaStream> stream) { m_mediaStreamSrcObject = stream; },
1414 #endif
1415 #if ENABLE(MEDIA_SOURCE)
1416                 [this](RefPtr<MediaSource> source) { m_mediaSource = source; },
1417 #endif
1418                 [this](RefPtr<Blob> blob) { m_blob = blob; }
1419             ), m_mediaProvider.value());
1420
1421             ContentType contentType;
1422             loadResource(URL(), contentType, String());
1423             ALWAYS_LOG(LOGIDENTIFIER, "using 'srcObject' property");
1424
1425             //    If that algorithm returns without aborting this one, then the load failed.
1426             // 4. Failed with media provider: Reaching this step indicates that the media resource
1427             //    failed to load. Queue a task to run the dedicated media source failure steps.
1428             // 5. Wait for the task queued by the previous step to have executed.
1429             // 6. Abort these steps. The element won’t attempt to load another resource until this
1430             //    algorithm is triggered again.
1431             return;
1432         }
1433
1434         // ↳ If mode is attribute
1435         if (mode == Attribute) {
1436             m_loadState = LoadingFromSrcAttr;
1437
1438             // 1. If the src attribute’s value is the empty string, then end the synchronous section,
1439             //    and jump down to the failed with attribute step below.
1440             // 2. Let absolute URL be the absolute URL that would have resulted from parsing the URL
1441             //    specified by the src attribute’s value relative to the media element when the src
1442             //    attribute was last changed.
1443             URL absoluteURL = getNonEmptyURLAttribute(srcAttr);
1444             if (absoluteURL.isEmpty()) {
1445                 mediaLoadingFailed(MediaPlayer::FormatError);
1446                 ALWAYS_LOG(LOGIDENTIFIER, "empty 'src'");
1447                 return;
1448             }
1449
1450             if (!isSafeToLoadURL(absoluteURL, Complain) || !dispatchBeforeLoadEvent(absoluteURL.string())) {
1451                 mediaLoadingFailed(MediaPlayer::FormatError);
1452                 return;
1453             }
1454
1455             // 3. If absolute URL was obtained successfully, set the currentSrc attribute to absolute URL.
1456             m_currentSrc = absoluteURL;
1457
1458             // 4. End the synchronous section, continuing the remaining steps in parallel.
1459             // 5. If absolute URL was obtained successfully, run the resource fetch algorithm with absolute
1460             //    URL. If that algorithm returns without aborting this one, then the load failed.
1461
1462             // No type or key system information is available when the url comes
1463             // from the 'src' attribute so MediaPlayer
1464             // will have to pick a media engine based on the file extension.
1465             ContentType contentType;
1466             loadResource(absoluteURL, contentType, String());
1467             ALWAYS_LOG(LOGIDENTIFIER, "using 'src' attribute url");
1468
1469             // 6. Failed with attribute: Reaching this step indicates that the media resource failed to load
1470             //    or that the given URL could not be resolved. Queue a task to run the dedicated media source failure steps.
1471             // 7. Wait for the task queued by the previous step to have executed.
1472             // 8. Abort these steps. The element won’t attempt to load another resource until this algorithm is triggered again.
1473             return;
1474         }
1475
1476         // ↳ Otherwise (mode is children)
1477         // (Ctd. in loadNextSourceChild())
1478         loadNextSourceChild();
1479     });
1480 }
1481
1482 void HTMLMediaElement::loadNextSourceChild()
1483 {
1484     ContentType contentType;
1485     String keySystem;
1486     URL mediaURL = selectNextSourceChild(&contentType, &keySystem, Complain);
1487     if (!mediaURL.isValid()) {
1488         waitForSourceChange();
1489         return;
1490     }
1491
1492     // Recreate the media player for the new url
1493     createMediaPlayer();
1494
1495     m_loadState = LoadingFromSourceElement;
1496     loadResource(mediaURL, contentType, keySystem);
1497 }
1498
1499 void HTMLMediaElement::loadResource(const URL& initialURL, ContentType& contentType, const String& keySystem)
1500 {
1501     ASSERT(initialURL.isEmpty() || isSafeToLoadURL(initialURL, Complain));
1502
1503     INFO_LOG(LOGIDENTIFIER, initialURL, contentType.raw(), keySystem);
1504
1505     RefPtr<Frame> frame = document().frame();
1506     if (!frame) {
1507         mediaLoadingFailed(MediaPlayer::FormatError);
1508         return;
1509     }
1510
1511     Page* page = frame->page();
1512     if (!page) {
1513         mediaLoadingFailed(MediaPlayer::FormatError);
1514         return;
1515     }
1516
1517     URL url = initialURL;
1518     if (!url.isEmpty() && !frame->loader().willLoadMediaElementURL(url)) {
1519         mediaLoadingFailed(MediaPlayer::FormatError);
1520         return;
1521     }
1522
1523 #if ENABLE(CONTENT_EXTENSIONS)
1524     if (auto* documentLoader = frame->loader().documentLoader()) {
1525         if (page->userContentProvider().processContentExtensionRulesForLoad(url, ResourceType::Media, *documentLoader).blockedLoad) {
1526             mediaLoadingFailed(MediaPlayer::FormatError);
1527             return;
1528         }
1529     }
1530 #endif
1531
1532     // The resource fetch algorithm
1533     m_networkState = NETWORK_LOADING;
1534
1535     // If the URL should be loaded from the application cache, pass the URL of the cached file to the media engine.
1536     ApplicationCacheResource* resource = nullptr;
1537     if (!url.isEmpty() && frame->loader().documentLoader()->applicationCacheHost().shouldLoadResourceFromApplicationCache(ResourceRequest(url), resource)) {
1538         // Resources that are not present in the manifest will always fail to load (at least, after the
1539         // cache has been primed the first time), making the testing of offline applications simpler.
1540         if (!resource || resource->path().isEmpty()) {
1541             mediaLoadingFailed(MediaPlayer::NetworkError);
1542             return;
1543         }
1544     }
1545
1546     // Log that we started loading a media element.
1547     page->diagnosticLoggingClient().logDiagnosticMessage(isVideo() ? DiagnosticLoggingKeys::videoKey() : DiagnosticLoggingKeys::audioKey(), DiagnosticLoggingKeys::loadingKey(), ShouldSample::No);
1548
1549     m_firstTimePlaying = true;
1550
1551     // Set m_currentSrc *before* changing to the cache URL, the fact that we are loading from the app
1552     // cache is an internal detail not exposed through the media element API.
1553     m_currentSrc = url;
1554
1555     if (resource) {
1556         url = ApplicationCacheHost::createFileURL(resource->path());
1557         INFO_LOG(LOGIDENTIFIER, "will load ", url, " from app cache");
1558     }
1559
1560     INFO_LOG(LOGIDENTIFIER, "m_currentSrc is ", m_currentSrc);
1561
1562     startProgressEventTimer();
1563
1564     bool privateMode = document().page() && document().page()->usesEphemeralSession();
1565     m_player->setPrivateBrowsingMode(privateMode);
1566
1567     // Reset display mode to force a recalculation of what to show because we are resetting the player.
1568     setDisplayMode(Unknown);
1569
1570     if (!autoplay() && !m_havePreparedToPlay)
1571         m_player->setPreload(m_mediaSession->effectivePreloadForElement(*this));
1572     m_player->setPreservesPitch(m_webkitPreservesPitch);
1573
1574     if (!m_explicitlyMuted) {
1575         m_explicitlyMuted = true;
1576         m_muted = hasAttributeWithoutSynchronization(mutedAttr);
1577         m_mediaSession->canProduceAudioChanged();
1578     }
1579
1580     updateVolume();
1581
1582     bool loadAttempted = false;
1583 #if ENABLE(MEDIA_SOURCE)
1584     if (!m_mediaSource && url.protocolIs(mediaSourceBlobProtocol))
1585         m_mediaSource = MediaSource::lookup(url.string());
1586
1587     if (m_mediaSource) {
1588         loadAttempted = true;
1589         if (!m_mediaSource->attachToElement(*this) || !m_player->load(url, contentType, m_mediaSource.get())) {
1590             // Forget our reference to the MediaSource, so we leave it alone
1591             // while processing remainder of load failure.
1592             m_mediaSource = nullptr;
1593             mediaLoadingFailed(MediaPlayer::FormatError);
1594         }
1595     }
1596 #endif
1597
1598 #if ENABLE(MEDIA_STREAM)
1599     if (!loadAttempted) {
1600         if (!m_mediaStreamSrcObject && url.protocolIs(mediaStreamBlobProtocol))
1601             m_mediaStreamSrcObject = MediaStreamRegistry::shared().lookUp(url);
1602
1603         if (m_mediaStreamSrcObject) {
1604             loadAttempted = true;
1605             if (!m_player->load(m_mediaStreamSrcObject->privateStream()))
1606                 mediaLoadingFailed(MediaPlayer::FormatError);
1607         }
1608     }
1609 #endif
1610
1611     if (!loadAttempted && m_blob) {
1612         loadAttempted = true;
1613         if (!m_player->load(m_blob->url(), contentType, keySystem))
1614             mediaLoadingFailed(MediaPlayer::FormatError);
1615     }
1616
1617     if (!loadAttempted && !m_player->load(url, contentType, keySystem))
1618         mediaLoadingFailed(MediaPlayer::FormatError);
1619
1620     // If there is no poster to display, allow the media engine to render video frames as soon as
1621     // they are available.
1622     updateDisplayState();
1623
1624     updateRenderer();
1625 }
1626
1627 #if ENABLE(VIDEO_TRACK)
1628
1629 static bool trackIndexCompare(TextTrack* a, TextTrack* b)
1630 {
1631     return a->trackIndex() - b->trackIndex() < 0;
1632 }
1633
1634 static bool eventTimeCueCompare(const std::pair<MediaTime, TextTrackCue*>& a, const std::pair<MediaTime, TextTrackCue*>& b)
1635 {
1636     // 12 - Sort the tasks in events in ascending time order (tasks with earlier
1637     // times first).
1638     if (a.first != b.first)
1639         return a.first - b.first < MediaTime::zeroTime();
1640
1641     // If the cues belong to different text tracks, it doesn't make sense to
1642     // compare the two tracks by the relative cue order, so return the relative
1643     // track order.
1644     if (a.second->track() != b.second->track())
1645         return trackIndexCompare(a.second->track(), b.second->track());
1646
1647     // 12 - Further sort tasks in events that have the same time by the
1648     // relative text track cue order of the text track cues associated
1649     // with these tasks.
1650     return a.second->isOrderedBefore(b.second);
1651 }
1652
1653 static bool compareCueInterval(const CueInterval& one, const CueInterval& two)
1654 {
1655     return one.data()->isOrderedBefore(two.data());
1656 }
1657
1658 void HTMLMediaElement::updateActiveTextTrackCues(const MediaTime& movieTime)
1659 {
1660     // 4.8.10.8 Playing the media resource
1661
1662     //  If the current playback position changes while the steps are running,
1663     //  then the user agent must wait for the steps to complete, and then must
1664     //  immediately rerun the steps.
1665     if (ignoreTrackDisplayUpdateRequests())
1666         return;
1667
1668     // 1 - Let current cues be a list of cues, initialized to contain all the
1669     // cues of all the hidden, showing, or showing by default text tracks of the
1670     // media element (not the disabled ones) whose start times are less than or
1671     // equal to the current playback position and whose end times are greater
1672     // than the current playback position.
1673     CueList currentCues;
1674
1675     // The user agent must synchronously unset [the text track cue active] flag
1676     // whenever ... the media element's readyState is changed back to HAVE_NOTHING.
1677     if (m_readyState != HAVE_NOTHING && m_player) {
1678         currentCues = m_cueTree.allOverlaps(m_cueTree.createInterval(movieTime, movieTime));
1679         if (currentCues.size() > 1)
1680             std::sort(currentCues.begin(), currentCues.end(), &compareCueInterval);
1681     }
1682
1683     CueList previousCues;
1684     CueList missedCues;
1685
1686     // 2 - Let other cues be a list of cues, initialized to contain all the cues
1687     // of hidden, showing, and showing by default text tracks of the media
1688     // element that are not present in current cues.
1689     previousCues = m_currentlyActiveCues;
1690
1691     // 3 - Let last time be the current playback position at the time this
1692     // algorithm was last run for this media element, if this is not the first
1693     // time it has run.
1694     MediaTime lastTime = m_lastTextTrackUpdateTime;
1695
1696     // 4 - If the current playback position has, since the last time this
1697     // algorithm was run, only changed through its usual monotonic increase
1698     // during normal playback, then let missed cues be the list of cues in other
1699     // cues whose start times are greater than or equal to last time and whose
1700     // end times are less than or equal to the current playback position.
1701     // Otherwise, let missed cues be an empty list.
1702     if (lastTime >= MediaTime::zeroTime() && m_lastSeekTime < movieTime) {
1703         for (auto& cue : m_cueTree.allOverlaps(m_cueTree.createInterval(lastTime, movieTime))) {
1704             // Consider cues that may have been missed since the last seek time.
1705             if (cue.low() > std::max(m_lastSeekTime, lastTime) && cue.high() < movieTime)
1706                 missedCues.append(cue);
1707         }
1708     }
1709
1710     m_lastTextTrackUpdateTime = movieTime;
1711
1712     // 5 - If the time was reached through the usual monotonic increase of the
1713     // current playback position during normal playback, and if the user agent
1714     // has not fired a timeupdate event at the element in the past 15 to 250ms
1715     // and is not still running event handlers for such an event, then the user
1716     // agent must queue a task to fire a simple event named timeupdate at the
1717     // element. (In the other cases, such as explicit seeks, relevant events get
1718     // fired as part of the overall process of changing the current playback
1719     // position.)
1720     if (!m_paused && m_lastSeekTime <= lastTime)
1721         scheduleTimeupdateEvent(false);
1722
1723     // Explicitly cache vector sizes, as their content is constant from here.
1724     size_t currentCuesSize = currentCues.size();
1725     size_t missedCuesSize = missedCues.size();
1726     size_t previousCuesSize = previousCues.size();
1727
1728     // 6 - If all of the cues in current cues have their text track cue active
1729     // flag set, none of the cues in other cues have their text track cue active
1730     // flag set, and missed cues is empty, then abort these steps.
1731     bool activeSetChanged = missedCuesSize;
1732
1733     for (size_t i = 0; !activeSetChanged && i < previousCuesSize; ++i)
1734         if (!currentCues.contains(previousCues[i]) && previousCues[i].data()->isActive())
1735             activeSetChanged = true;
1736
1737     for (size_t i = 0; i < currentCuesSize; ++i) {
1738         RefPtr<TextTrackCue> cue = currentCues[i].data();
1739
1740         if (cue->isRenderable())
1741             toVTTCue(cue.get())->updateDisplayTree(movieTime);
1742
1743         if (!cue->isActive())
1744             activeSetChanged = true;
1745     }
1746
1747     if (!activeSetChanged)
1748         return;
1749
1750     // 7 - If the time was reached through the usual monotonic increase of the
1751     // current playback position during normal playback, and there are cues in
1752     // other cues that have their text track cue pause-on-exi flag set and that
1753     // either have their text track cue active flag set or are also in missed
1754     // cues, then immediately pause the media element.
1755     for (size_t i = 0; !m_paused && i < previousCuesSize; ++i) {
1756         if (previousCues[i].data()->pauseOnExit()
1757             && previousCues[i].data()->isActive()
1758             && !currentCues.contains(previousCues[i]))
1759             pause();
1760     }
1761
1762     for (size_t i = 0; !m_paused && i < missedCuesSize; ++i) {
1763         if (missedCues[i].data()->pauseOnExit())
1764             pause();
1765     }
1766
1767     // 8 - Let events be a list of tasks, initially empty. Each task in this
1768     // list will be associated with a text track, a text track cue, and a time,
1769     // which are used to sort the list before the tasks are queued.
1770     Vector<std::pair<MediaTime, TextTrackCue*>> eventTasks;
1771
1772     // 8 - Let affected tracks be a list of text tracks, initially empty.
1773     Vector<TextTrack*> affectedTracks;
1774
1775     for (size_t i = 0; i < missedCuesSize; ++i) {
1776         // 9 - For each text track cue in missed cues, prepare an event named enter
1777         // for the TextTrackCue object with the text track cue start time.
1778         eventTasks.append({ missedCues[i].data()->startMediaTime(), missedCues[i].data() });
1779
1780         // 10 - For each text track [...] in missed cues, prepare an event
1781         // named exit for the TextTrackCue object with the  with the later of
1782         // the text track cue end time and the text track cue start time.
1783
1784         // Note: An explicit task is added only if the cue is NOT a zero or
1785         // negative length cue. Otherwise, the need for an exit event is
1786         // checked when these tasks are actually queued below. This doesn't
1787         // affect sorting events before dispatch either, because the exit
1788         // event has the same time as the enter event.
1789         if (missedCues[i].data()->startMediaTime() < missedCues[i].data()->endMediaTime())
1790             eventTasks.append({ missedCues[i].data()->endMediaTime(), missedCues[i].data() });
1791     }
1792
1793     for (size_t i = 0; i < previousCuesSize; ++i) {
1794         // 10 - For each text track cue in other cues that has its text
1795         // track cue active flag set prepare an event named exit for the
1796         // TextTrackCue object with the text track cue end time.
1797         if (!currentCues.contains(previousCues[i]))
1798             eventTasks.append({ previousCues[i].data()->endMediaTime(), previousCues[i].data() });
1799     }
1800
1801     for (size_t i = 0; i < currentCuesSize; ++i) {
1802         // 11 - For each text track cue in current cues that does not have its
1803         // text track cue active flag set, prepare an event named enter for the
1804         // TextTrackCue object with the text track cue start time.
1805         if (!previousCues.contains(currentCues[i]))
1806             eventTasks.append({ currentCues[i].data()->startMediaTime(), currentCues[i].data() });
1807     }
1808
1809     // 12 - Sort the tasks in events in ascending time order (tasks with earlier
1810     // times first).
1811     std::sort(eventTasks.begin(), eventTasks.end(), eventTimeCueCompare);
1812
1813     for (auto& eventTask : eventTasks) {
1814         if (!affectedTracks.contains(eventTask.second->track()))
1815             affectedTracks.append(eventTask.second->track());
1816
1817         // 13 - Queue each task in events, in list order.
1818
1819         // Each event in eventTasks may be either an enterEvent or an exitEvent,
1820         // depending on the time that is associated with the event. This
1821         // correctly identifies the type of the event, if the startTime is
1822         // less than the endTime in the cue.
1823         if (eventTask.second->startTime() >= eventTask.second->endTime()) {
1824             auto enterEvent = Event::create(eventNames().enterEvent, false, false);
1825             enterEvent->setTarget(eventTask.second);
1826             m_asyncEventQueue.enqueueEvent(WTFMove(enterEvent));
1827
1828             auto exitEvent = Event::create(eventNames().exitEvent, false, false);
1829             exitEvent->setTarget(eventTask.second);
1830             m_asyncEventQueue.enqueueEvent(WTFMove(exitEvent));
1831         } else {
1832             RefPtr<Event> event;
1833             if (eventTask.first == eventTask.second->startMediaTime())
1834                 event = Event::create(eventNames().enterEvent, false, false);
1835             else
1836                 event = Event::create(eventNames().exitEvent, false, false);
1837             event->setTarget(eventTask.second);
1838             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1839         }
1840     }
1841
1842     // 14 - Sort affected tracks in the same order as the text tracks appear in
1843     // the media element's list of text tracks, and remove duplicates.
1844     std::sort(affectedTracks.begin(), affectedTracks.end(), trackIndexCompare);
1845
1846     // 15 - For each text track in affected tracks, in the list order, queue a
1847     // task to fire a simple event named cuechange at the TextTrack object, and, ...
1848     for (auto& affectedTrack : affectedTracks) {
1849         auto event = Event::create(eventNames().cuechangeEvent, false, false);
1850         event->setTarget(affectedTrack);
1851         m_asyncEventQueue.enqueueEvent(WTFMove(event));
1852
1853         // ... if the text track has a corresponding track element, to then fire a
1854         // simple event named cuechange at the track element as well.
1855         if (is<LoadableTextTrack>(*affectedTrack)) {
1856             auto event = Event::create(eventNames().cuechangeEvent, false, false);
1857             auto* trackElement = downcast<LoadableTextTrack>(*affectedTrack).trackElement();
1858             ASSERT(trackElement);
1859             event->setTarget(trackElement);
1860             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1861         }
1862     }
1863
1864     // 16 - Set the text track cue active flag of all the cues in the current
1865     // cues, and unset the text track cue active flag of all the cues in the
1866     // other cues.
1867     for (size_t i = 0; i < currentCuesSize; ++i)
1868         currentCues[i].data()->setIsActive(true);
1869
1870     for (size_t i = 0; i < previousCuesSize; ++i)
1871         if (!currentCues.contains(previousCues[i]))
1872             previousCues[i].data()->setIsActive(false);
1873
1874     // Update the current active cues.
1875     m_currentlyActiveCues = currentCues;
1876
1877     if (activeSetChanged)
1878         updateTextTrackDisplay();
1879 }
1880
1881 bool HTMLMediaElement::textTracksAreReady() const
1882 {
1883     // 4.8.10.12.1 Text track model
1884     // ...
1885     // The text tracks of a media element are ready if all the text tracks whose mode was not
1886     // in the disabled state when the element's resource selection algorithm last started now
1887     // have a text track readiness state of loaded or failed to load.
1888     for (unsigned i = 0; i < m_textTracksWhenResourceSelectionBegan.size(); ++i) {
1889         if (m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::Loading
1890             || m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::NotLoaded)
1891             return false;
1892     }
1893
1894     return true;
1895 }
1896
1897 void HTMLMediaElement::textTrackReadyStateChanged(TextTrack* track)
1898 {
1899     if (track->readinessState() != TextTrack::Loading
1900         && track->mode() != TextTrack::Mode::Disabled) {
1901         // The display trees exist as long as the track is active, in this case,
1902         // and if the same track is loaded again (for example if the src attribute was changed),
1903         // cues can be accumulated with the old ones, that's why they needs to be flushed
1904         if (hasMediaControls())
1905             mediaControls()->clearTextDisplayContainer();
1906         updateTextTrackDisplay();
1907     }
1908     if (m_player && m_textTracksWhenResourceSelectionBegan.contains(track)) {
1909         if (track->readinessState() != TextTrack::Loading)
1910             setReadyState(m_player->readyState());
1911     } else {
1912         // The track readiness state might have changed as a result of the user
1913         // clicking the captions button. In this case, a check whether all the
1914         // resources have failed loading should be done in order to hide the CC button.
1915         if (hasMediaControls() && track->readinessState() == TextTrack::FailedToLoad)
1916             mediaControls()->refreshClosedCaptionsButtonVisibility();
1917     }
1918 }
1919
1920 void HTMLMediaElement::audioTrackEnabledChanged(AudioTrack& track)
1921 {
1922     if (m_audioTracks && m_audioTracks->contains(track))
1923         m_audioTracks->scheduleChangeEvent();
1924     if (processingUserGestureForMedia())
1925         removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager);
1926 }
1927
1928 void HTMLMediaElement::textTrackModeChanged(TextTrack& track)
1929 {
1930     bool trackIsLoaded = true;
1931     if (track.trackType() == TextTrack::TrackElement) {
1932         trackIsLoaded = false;
1933         for (auto& trackElement : childrenOfType<HTMLTrackElement>(*this)) {
1934             if (&trackElement.track() == &track) {
1935                 if (trackElement.readyState() == HTMLTrackElement::LOADING || trackElement.readyState() == HTMLTrackElement::LOADED)
1936                     trackIsLoaded = true;
1937                 break;
1938             }
1939         }
1940     }
1941
1942     // If this is the first added track, create the list of text tracks.
1943     if (!m_textTracks)
1944         m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
1945
1946     // Mark this track as "configured" so configureTextTracks won't change the mode again.
1947     track.setHasBeenConfigured(true);
1948
1949     if (track.mode() != TextTrack::Mode::Disabled && trackIsLoaded)
1950         textTrackAddCues(track, *track.cues());
1951
1952     configureTextTrackDisplay(AssumeTextTrackVisibilityChanged);
1953
1954     if (m_textTracks && m_textTracks->contains(track))
1955         m_textTracks->scheduleChangeEvent();
1956
1957 #if ENABLE(AVF_CAPTIONS)
1958     if (track.trackType() == TextTrack::TrackElement && m_player)
1959         m_player->notifyTrackModeChanged();
1960 #endif
1961 }
1962
1963 void HTMLMediaElement::videoTrackSelectedChanged(VideoTrack& track)
1964 {
1965     if (m_videoTracks && m_videoTracks->contains(track))
1966         m_videoTracks->scheduleChangeEvent();
1967 }
1968
1969 void HTMLMediaElement::textTrackKindChanged(TextTrack& track)
1970 {
1971     if (track.kind() != TextTrack::Kind::Captions && track.kind() != TextTrack::Kind::Subtitles && track.mode() == TextTrack::Mode::Showing)
1972         track.setMode(TextTrack::Mode::Hidden);
1973 }
1974
1975 void HTMLMediaElement::beginIgnoringTrackDisplayUpdateRequests()
1976 {
1977     ++m_ignoreTrackDisplayUpdate;
1978 }
1979
1980 void HTMLMediaElement::endIgnoringTrackDisplayUpdateRequests()
1981 {
1982     ASSERT(m_ignoreTrackDisplayUpdate);
1983     --m_ignoreTrackDisplayUpdate;
1984     if (!m_ignoreTrackDisplayUpdate && m_inActiveDocument)
1985         updateActiveTextTrackCues(currentMediaTime());
1986 }
1987
1988 void HTMLMediaElement::textTrackAddCues(TextTrack& track, const TextTrackCueList& cues)
1989 {
1990     if (track.mode() == TextTrack::Mode::Disabled)
1991         return;
1992
1993     TrackDisplayUpdateScope scope { *this };
1994     for (unsigned i = 0; i < cues.length(); ++i)
1995         textTrackAddCue(track, *cues.item(i));
1996 }
1997
1998 void HTMLMediaElement::textTrackRemoveCues(TextTrack&, const TextTrackCueList& cues)
1999 {
2000     TrackDisplayUpdateScope scope { *this };
2001     for (unsigned i = 0; i < cues.length(); ++i) {
2002         auto& cue = *cues.item(i);
2003         textTrackRemoveCue(*cue.track(), cue);
2004     }
2005 }
2006
2007 void HTMLMediaElement::textTrackAddCue(TextTrack& track, TextTrackCue& cue)
2008 {
2009     if (track.mode() == TextTrack::Mode::Disabled)
2010         return;
2011
2012     // Negative duration cues need be treated in the interval tree as
2013     // zero-length cues.
2014     MediaTime endTime = std::max(cue.startMediaTime(), cue.endMediaTime());
2015
2016     CueInterval interval = m_cueTree.createInterval(cue.startMediaTime(), endTime, &cue);
2017     if (!m_cueTree.contains(interval))
2018         m_cueTree.add(interval);
2019     updateActiveTextTrackCues(currentMediaTime());
2020 }
2021
2022 void HTMLMediaElement::textTrackRemoveCue(TextTrack&, TextTrackCue& cue)
2023 {
2024     // Negative duration cues need to be treated in the interval tree as
2025     // zero-length cues.
2026     MediaTime endTime = std::max(cue.startMediaTime(), cue.endMediaTime());
2027
2028     CueInterval interval = m_cueTree.createInterval(cue.startMediaTime(), endTime, &cue);
2029     m_cueTree.remove(interval);
2030
2031     // Since the cue will be removed from the media element and likely the
2032     // TextTrack might also be destructed, notifying the region of the cue
2033     // removal shouldn't be done.
2034     if (cue.isRenderable())
2035         toVTTCue(&cue)->notifyRegionWhenRemovingDisplayTree(false);
2036
2037     size_t index = m_currentlyActiveCues.find(interval);
2038     if (index != notFound) {
2039         cue.setIsActive(false);
2040         m_currentlyActiveCues.remove(index);
2041     }
2042
2043     if (cue.isRenderable())
2044         toVTTCue(&cue)->removeDisplayTree();
2045     updateActiveTextTrackCues(currentMediaTime());
2046
2047     if (cue.isRenderable())
2048         toVTTCue(&cue)->notifyRegionWhenRemovingDisplayTree(true);
2049 }
2050
2051 #endif
2052
2053 static inline bool isAllowedToLoadMediaURL(HTMLMediaElement& element, const URL& url, bool isInUserAgentShadowTree)
2054 {
2055     // Elements in user agent show tree should load whatever the embedding document policy is.
2056     if (isInUserAgentShadowTree)
2057         return true;
2058
2059     ASSERT(element.document().contentSecurityPolicy());
2060     return element.document().contentSecurityPolicy()->allowMediaFromSource(url);
2061 }
2062
2063 bool HTMLMediaElement::isSafeToLoadURL(const URL& url, InvalidURLAction actionIfInvalid)
2064 {
2065     if (!url.isValid()) {
2066         ERROR_LOG(LOGIDENTIFIER, url, " is invalid");
2067         return false;
2068     }
2069
2070     RefPtr<Frame> frame = document().frame();
2071     if (!frame || !document().securityOrigin().canDisplay(url)) {
2072         if (actionIfInvalid == Complain)
2073             FrameLoader::reportLocalLoadFailed(frame.get(), url.stringCenterEllipsizedToLength());
2074             ERROR_LOG(LOGIDENTIFIER, url , " was rejected by SecurityOrigin");
2075         return false;
2076     }
2077
2078     if (!isAllowedToLoadMediaURL(*this, url, isInUserAgentShadowTree())) {
2079         ERROR_LOG(LOGIDENTIFIER, url, " was rejected by Content Security Policy");
2080         return false;
2081     }
2082
2083     return true;
2084 }
2085
2086 void HTMLMediaElement::startProgressEventTimer()
2087 {
2088     if (m_progressEventTimer.isActive())
2089         return;
2090
2091     m_previousProgressTime = monotonicallyIncreasingTime();
2092     // 350ms is not magic, it is in the spec!
2093     m_progressEventTimer.startRepeating(350_ms);
2094 }
2095
2096 void HTMLMediaElement::waitForSourceChange()
2097 {
2098     INFO_LOG(LOGIDENTIFIER);
2099
2100     stopPeriodicTimers();
2101     m_loadState = WaitingForSource;
2102
2103     // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
2104     m_networkState = NETWORK_NO_SOURCE;
2105
2106     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
2107     setShouldDelayLoadEvent(false);
2108
2109     updateDisplayState();
2110     updateRenderer();
2111 }
2112
2113 void HTMLMediaElement::noneSupported()
2114 {
2115     INFO_LOG(LOGIDENTIFIER);
2116
2117     stopPeriodicTimers();
2118     m_loadState = WaitingForSource;
2119     m_currentSourceNode = nullptr;
2120
2121     // 4.8.10.5
2122     // 6 - Reaching this step indicates that the media resource failed to load or that the given
2123     // URL could not be resolved. In one atomic operation, run the following steps:
2124
2125     // 6.1 - Set the error attribute to a new MediaError object whose code attribute is set to
2126     // MEDIA_ERR_SRC_NOT_SUPPORTED.
2127     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
2128
2129     // 6.2 - Forget the media element's media-resource-specific text tracks.
2130     forgetResourceSpecificTracks();
2131
2132     // 6.3 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
2133     m_networkState = NETWORK_NO_SOURCE;
2134
2135     // 7 - Queue a task to fire a simple event named error at the media element.
2136     scheduleEvent(eventNames().errorEvent);
2137
2138     rejectPendingPlayPromises(DOMException::create(NotSupportedError));
2139
2140 #if ENABLE(MEDIA_SOURCE)
2141     detachMediaSource();
2142 #endif
2143
2144     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
2145     setShouldDelayLoadEvent(false);
2146
2147     // 9 - Abort these steps. Until the load() method is invoked or the src attribute is changed,
2148     // the element won't attempt to load another resource.
2149
2150     updateDisplayState();
2151     updateRenderer();
2152 }
2153
2154 void HTMLMediaElement::mediaLoadingFailedFatally(MediaPlayer::NetworkState error)
2155 {
2156     // 1 - The user agent should cancel the fetching process.
2157     stopPeriodicTimers();
2158     m_loadState = WaitingForSource;
2159
2160     // 2 - Set the error attribute to a new MediaError object whose code attribute is
2161     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
2162     if (error == MediaPlayer::NetworkError)
2163         m_error = MediaError::create(MediaError::MEDIA_ERR_NETWORK);
2164     else if (error == MediaPlayer::DecodeError)
2165         m_error = MediaError::create(MediaError::MEDIA_ERR_DECODE);
2166     else
2167         ASSERT_NOT_REACHED();
2168
2169     // 3 - Queue a task to fire a simple event named error at the media element.
2170     scheduleEvent(eventNames().errorEvent);
2171
2172 #if ENABLE(MEDIA_SOURCE)
2173     detachMediaSource();
2174 #endif
2175
2176     // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
2177     // task to fire a simple event called emptied at the element.
2178     m_networkState = NETWORK_EMPTY;
2179     scheduleEvent(eventNames().emptiedEvent);
2180
2181     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
2182     setShouldDelayLoadEvent(false);
2183
2184     // 6 - Abort the overall resource selection algorithm.
2185     m_currentSourceNode = nullptr;
2186
2187 #if PLATFORM(COCOA)
2188     if (is<MediaDocument>(document()))
2189         downcast<MediaDocument>(document()).mediaElementSawUnsupportedTracks();
2190 #endif
2191 }
2192
2193 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
2194 {
2195     INFO_LOG(LOGIDENTIFIER);
2196     m_asyncEventQueue.cancelAllEvents();
2197
2198     for (auto& source : childrenOfType<HTMLSourceElement>(*this))
2199         source.cancelPendingErrorEvent();
2200
2201     rejectPendingPlayPromises(DOMException::create(AbortError));
2202 }
2203
2204 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
2205 {
2206     beginProcessingMediaPlayerCallback();
2207     setNetworkState(m_player->networkState());
2208     endProcessingMediaPlayerCallback();
2209 }
2210
2211 static void logMediaLoadRequest(Page* page, const String& mediaEngine, const String& errorMessage, bool succeeded)
2212 {
2213     if (!page)
2214         return;
2215
2216     DiagnosticLoggingClient& diagnosticLoggingClient = page->diagnosticLoggingClient();
2217     if (!succeeded) {
2218         diagnosticLoggingClient.logDiagnosticMessageWithResult(DiagnosticLoggingKeys::mediaLoadingFailedKey(), errorMessage, DiagnosticLoggingResultFail, ShouldSample::No);
2219         return;
2220     }
2221
2222     diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::mediaLoadedKey(), mediaEngine, ShouldSample::No);
2223
2224     if (!page->hasSeenAnyMediaEngine())
2225         diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsAtLeastOneMediaEngineKey(), emptyString(), ShouldSample::No);
2226
2227     if (!page->hasSeenMediaEngine(mediaEngine))
2228         diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsMediaEngineKey(), mediaEngine, ShouldSample::No);
2229
2230     page->sawMediaEngine(mediaEngine);
2231 }
2232
2233 static String stringForNetworkState(MediaPlayer::NetworkState state)
2234 {
2235     switch (state) {
2236     case MediaPlayer::Empty: return ASCIILiteral("Empty");
2237     case MediaPlayer::Idle: return ASCIILiteral("Idle");
2238     case MediaPlayer::Loading: return ASCIILiteral("Loading");
2239     case MediaPlayer::Loaded: return ASCIILiteral("Loaded");
2240     case MediaPlayer::FormatError: return ASCIILiteral("FormatError");
2241     case MediaPlayer::NetworkError: return ASCIILiteral("NetworkError");
2242     case MediaPlayer::DecodeError: return ASCIILiteral("DecodeError");
2243     default: return emptyString();
2244     }
2245 }
2246
2247 void HTMLMediaElement::mediaLoadingFailed(MediaPlayer::NetworkState error)
2248 {
2249     stopPeriodicTimers();
2250
2251     // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
2252     // <source> children, schedule the next one
2253     if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
2254
2255         // resource selection algorithm
2256         // Step 9.Otherwise.9 - Failed with elements: Queue a task, using the DOM manipulation task source, to fire a simple event named error at the candidate element.
2257         if (m_currentSourceNode)
2258             m_currentSourceNode->scheduleErrorEvent();
2259         else
2260             INFO_LOG(LOGIDENTIFIER, "error event not sent, <source> was removed");
2261
2262         // 9.Otherwise.10 - Asynchronously await a stable state. The synchronous section consists of all the remaining steps of this algorithm until the algorithm says the synchronous section has ended.
2263
2264         // 9.Otherwise.11 - Forget the media element's media-resource-specific tracks.
2265         forgetResourceSpecificTracks();
2266
2267         if (havePotentialSourceChild()) {
2268             INFO_LOG(LOGIDENTIFIER, "scheduling next <source>");
2269             scheduleNextSourceChild();
2270         } else {
2271             INFO_LOG(LOGIDENTIFIER, "no more <source> elements, waiting");
2272             waitForSourceChange();
2273         }
2274
2275         return;
2276     }
2277
2278     if ((error == MediaPlayer::NetworkError && m_readyState >= HAVE_METADATA) || error == MediaPlayer::DecodeError)
2279         mediaLoadingFailedFatally(error);
2280     else if ((error == MediaPlayer::FormatError || error == MediaPlayer::NetworkError) && m_loadState == LoadingFromSrcAttr)
2281         noneSupported();
2282
2283     updateDisplayState();
2284     if (hasMediaControls()) {
2285         mediaControls()->reset();
2286         mediaControls()->reportedError();
2287     }
2288
2289     ERROR_LOG(LOGIDENTIFIER, "error = ", static_cast<int>(error));
2290
2291     logMediaLoadRequest(document().page(), String(), stringForNetworkState(error), false);
2292
2293     m_mediaSession->clientCharacteristicsChanged();
2294 }
2295
2296 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
2297 {
2298     if (static_cast<int>(state) != static_cast<int>(m_networkState))
2299         ALWAYS_LOG(LOGIDENTIFIER, "new state = ", static_cast<int>(state), ", current state = ", static_cast<int>(m_networkState));
2300
2301     if (state == MediaPlayer::Empty) {
2302         // Just update the cached state and leave, we can't do anything.
2303         m_networkState = NETWORK_EMPTY;
2304         return;
2305     }
2306
2307     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
2308         mediaLoadingFailed(state);
2309         return;
2310     }
2311
2312     if (state == MediaPlayer::Idle) {
2313         if (m_networkState > NETWORK_IDLE) {
2314             changeNetworkStateFromLoadingToIdle();
2315             setShouldDelayLoadEvent(false);
2316         } else {
2317             m_networkState = NETWORK_IDLE;
2318         }
2319     }
2320
2321     if (state == MediaPlayer::Loading) {
2322         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
2323             startProgressEventTimer();
2324         m_networkState = NETWORK_LOADING;
2325     }
2326
2327     if (state == MediaPlayer::Loaded) {
2328         if (m_networkState != NETWORK_IDLE)
2329             changeNetworkStateFromLoadingToIdle();
2330         m_completelyLoaded = true;
2331     }
2332
2333     if (hasMediaControls())
2334         mediaControls()->updateStatusDisplay();
2335 }
2336
2337 void HTMLMediaElement::changeNetworkStateFromLoadingToIdle()
2338 {
2339     m_progressEventTimer.stop();
2340     if (hasMediaControls() && m_player->didLoadingProgress())
2341         mediaControls()->bufferingProgressed();
2342
2343     // Schedule one last progress event so we guarantee that at least one is fired
2344     // for files that load very quickly.
2345     scheduleEvent(eventNames().progressEvent);
2346     scheduleEvent(eventNames().suspendEvent);
2347     m_networkState = NETWORK_IDLE;
2348 }
2349
2350 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
2351 {
2352     beginProcessingMediaPlayerCallback();
2353
2354     setReadyState(m_player->readyState());
2355
2356     endProcessingMediaPlayerCallback();
2357 }
2358
2359 SuccessOr<MediaPlaybackDenialReason> HTMLMediaElement::canTransitionFromAutoplayToPlay() const
2360 {
2361     if (isAutoplaying()
2362         && mediaSession().autoplayPermitted()
2363         && paused()
2364         && autoplay()
2365         && !pausedForUserInteraction()
2366         && !document().isSandboxed(SandboxAutomaticFeatures)
2367         && m_readyState == HAVE_ENOUGH_DATA)
2368         return mediaSession().playbackPermitted(*this);
2369
2370     ALWAYS_LOG(LOGIDENTIFIER, "page consent required");
2371     return MediaPlaybackDenialReason::PageConsentRequired;
2372 }
2373
2374 void HTMLMediaElement::dispatchPlayPauseEventsIfNeedsQuirks()
2375 {
2376     auto& document = this->document();
2377     if (!needsAutoplayPlayPauseEventsQuirk(document) && !needsAutoplayPlayPauseEventsQuirk(document.topDocument()))
2378         return;
2379
2380     scheduleEvent(eventNames().playingEvent);
2381     scheduleEvent(eventNames().pauseEvent);
2382 }
2383
2384 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
2385 {
2386     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
2387     bool wasPotentiallyPlaying = potentiallyPlaying();
2388
2389     ReadyState oldState = m_readyState;
2390     ReadyState newState = static_cast<ReadyState>(state);
2391
2392 #if ENABLE(VIDEO_TRACK)
2393     bool tracksAreReady = textTracksAreReady();
2394
2395     if (newState == oldState && m_tracksAreReady == tracksAreReady)
2396         return;
2397
2398     m_tracksAreReady = tracksAreReady;
2399 #else
2400     if (newState == oldState)
2401         return;
2402     bool tracksAreReady = true;
2403 #endif
2404
2405     ALWAYS_LOG(LOGIDENTIFIER, "new state = ", static_cast<int>(state), ", current state = ", static_cast<int>(m_readyState));
2406
2407     if (tracksAreReady)
2408         m_readyState = newState;
2409     else {
2410         // If a media file has text tracks the readyState may not progress beyond HAVE_FUTURE_DATA until
2411         // the text tracks are ready, regardless of the state of the media file.
2412         if (newState <= HAVE_METADATA)
2413             m_readyState = newState;
2414         else
2415             m_readyState = HAVE_CURRENT_DATA;
2416     }
2417
2418     if (oldState > m_readyStateMaximum)
2419         m_readyStateMaximum = oldState;
2420
2421     if (m_networkState == NETWORK_EMPTY)
2422         return;
2423
2424     if (m_seeking) {
2425         // 4.8.10.9, step 11
2426         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
2427             scheduleEvent(eventNames().waitingEvent);
2428
2429         // 4.8.10.10 step 14 & 15.
2430         if (m_seekRequested && !m_player->seeking() && m_readyState >= HAVE_CURRENT_DATA)
2431             finishSeek();
2432     } else {
2433         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
2434             // 4.8.10.8
2435             invalidateCachedTime();
2436             scheduleTimeupdateEvent(false);
2437             scheduleEvent(eventNames().waitingEvent);
2438         }
2439     }
2440
2441     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
2442         prepareMediaFragmentURI();
2443         scheduleEvent(eventNames().durationchangeEvent);
2444         scheduleResizeEvent();
2445         scheduleEvent(eventNames().loadedmetadataEvent);
2446 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
2447         if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent))
2448             enqueuePlaybackTargetAvailabilityChangedEvent();
2449 #endif
2450         m_initiallyMuted = m_volume < 0.05 || muted();
2451
2452         if (hasMediaControls())
2453             mediaControls()->loadedMetadata();
2454         updateRenderer();
2455
2456         if (is<MediaDocument>(document()))
2457             downcast<MediaDocument>(document()).mediaElementNaturalSizeChanged(expandedIntSize(m_player->naturalSize()));
2458
2459         logMediaLoadRequest(document().page(), m_player->engineDescription(), String(), true);
2460
2461 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
2462         updateMediaState(UpdateState::Asynchronously);
2463 #endif
2464
2465         m_mediaSession->clientCharacteristicsChanged();
2466     }
2467
2468     bool shouldUpdateDisplayState = false;
2469
2470     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA) {
2471         if (!m_haveFiredLoadedData) {
2472             m_haveFiredLoadedData = true;
2473             scheduleEvent(eventNames().loadeddataEvent);
2474             // FIXME: It's not clear that it's correct to skip these two operations just
2475             // because m_haveFiredLoadedData is already true. At one time we were skipping
2476             // the call to setShouldDelayLoadEvent, which was definitely incorrect.
2477             shouldUpdateDisplayState = true;
2478             applyMediaFragmentURI();
2479         }
2480         setShouldDelayLoadEvent(false);
2481     }
2482
2483     bool isPotentiallyPlaying = potentiallyPlaying();
2484     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) {
2485         scheduleEvent(eventNames().canplayEvent);
2486         if (isPotentiallyPlaying)
2487             scheduleNotifyAboutPlaying();
2488         shouldUpdateDisplayState = true;
2489     }
2490
2491     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && tracksAreReady) {
2492         if (oldState <= HAVE_CURRENT_DATA)
2493             scheduleEvent(eventNames().canplayEvent);
2494
2495         scheduleEvent(eventNames().canplaythroughEvent);
2496
2497         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
2498             scheduleNotifyAboutPlaying();
2499
2500         auto success = canTransitionFromAutoplayToPlay();
2501         if (success) {
2502             m_paused = false;
2503             invalidateCachedTime();
2504             setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Started);
2505             m_playbackStartedTime = currentMediaTime().toDouble();
2506             scheduleEvent(eventNames().playEvent);
2507             scheduleNotifyAboutPlaying();
2508         } else if (success.value() == MediaPlaybackDenialReason::UserGestureRequired)
2509             setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
2510
2511         shouldUpdateDisplayState = true;
2512     }
2513
2514     // If we transition to the Future Data state and we're about to begin playing, ensure playback is actually permitted first,
2515     // honoring any playback denial reasons such as the requirement of a user gesture.
2516     if (m_readyState == HAVE_FUTURE_DATA && oldState < HAVE_FUTURE_DATA && potentiallyPlaying() && !m_mediaSession->playbackPermitted(*this)) {
2517         pauseInternal();
2518         setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
2519     }
2520
2521     if (shouldUpdateDisplayState) {
2522         updateDisplayState();
2523         if (hasMediaControls()) {
2524             mediaControls()->refreshClosedCaptionsButtonVisibility();
2525             mediaControls()->updateStatusDisplay();
2526         }
2527     }
2528
2529     updatePlayState();
2530     updateMediaController();
2531 #if ENABLE(VIDEO_TRACK)
2532     updateActiveTextTrackCues(currentMediaTime());
2533 #endif
2534 }
2535
2536 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
2537 RefPtr<ArrayBuffer> HTMLMediaElement::mediaPlayerCachedKeyForKeyId(const String& keyId) const
2538 {
2539     return m_webKitMediaKeys ? m_webKitMediaKeys->cachedKeyForKeyId(keyId) : nullptr;
2540 }
2541
2542 bool HTMLMediaElement::mediaPlayerKeyNeeded(MediaPlayer*, Uint8Array* initData)
2543 {
2544     if (!RuntimeEnabledFeatures::sharedFeatures().legacyEncryptedMediaAPIEnabled())
2545         return false;
2546
2547     if (!hasEventListeners("webkitneedkey")) {
2548         m_error = MediaError::create(MediaError::MEDIA_ERR_ENCRYPTED);
2549         scheduleEvent(eventNames().errorEvent);
2550         return false;
2551     }
2552
2553     auto event = WebKitMediaKeyNeededEvent::create(eventNames().webkitneedkeyEvent, initData);
2554     event->setTarget(this);
2555     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2556
2557     return true;
2558 }
2559
2560 String HTMLMediaElement::mediaPlayerMediaKeysStorageDirectory() const
2561 {
2562     auto* page = document().page();
2563     if (!page || page->usesEphemeralSession())
2564         return emptyString();
2565
2566     String storageDirectory = document().settings().mediaKeysStorageDirectory();
2567     if (storageDirectory.isEmpty())
2568         return emptyString();
2569
2570     return FileSystem::pathByAppendingComponent(storageDirectory, SecurityOriginData::fromSecurityOrigin(document().securityOrigin()).databaseIdentifier());
2571 }
2572
2573 void HTMLMediaElement::webkitSetMediaKeys(WebKitMediaKeys* mediaKeys)
2574 {
2575     if (!RuntimeEnabledFeatures::sharedFeatures().legacyEncryptedMediaAPIEnabled())
2576         return;
2577
2578     if (m_webKitMediaKeys == mediaKeys)
2579         return;
2580
2581     if (m_webKitMediaKeys)
2582         m_webKitMediaKeys->setMediaElement(nullptr);
2583     m_webKitMediaKeys = mediaKeys;
2584     if (m_webKitMediaKeys)
2585         m_webKitMediaKeys->setMediaElement(this);
2586 }
2587
2588 void HTMLMediaElement::keyAdded()
2589 {
2590     if (!RuntimeEnabledFeatures::sharedFeatures().legacyEncryptedMediaAPIEnabled())
2591         return;
2592
2593     if (m_player)
2594         m_player->keyAdded();
2595 }
2596
2597 #endif
2598
2599 #if ENABLE(ENCRYPTED_MEDIA)
2600
2601 MediaKeys* HTMLMediaElement::mediaKeys() const
2602 {
2603     return m_mediaKeys.get();
2604 }
2605
2606 void HTMLMediaElement::setMediaKeys(MediaKeys* mediaKeys, Ref<DeferredPromise>&& promise)
2607 {
2608     // https://w3c.github.io/encrypted-media/#dom-htmlmediaelement-setmediakeys
2609     // W3C Editor's Draft 23 June 2017
2610
2611     // 1. If this object's attaching media keys value is true, return a promise rejected with an InvalidStateError.
2612     if (m_attachingMediaKeys) {
2613         promise->reject(InvalidStateError);
2614         return;
2615     }
2616
2617     // 2. If mediaKeys and the mediaKeys attribute are the same object, return a resolved promise.
2618     if (mediaKeys == m_mediaKeys) {
2619         promise->resolve();
2620         return;
2621     }
2622
2623     // 3. Let this object's attaching media keys value be true.
2624     m_attachingMediaKeys = true;
2625
2626     // 4. Let promise be a new promise.
2627     // 5. Run the following steps in parallel:
2628     m_encryptedMediaQueue.enqueueTask([this, mediaKeys = RefPtr<MediaKeys>(mediaKeys), promise = WTFMove(promise)]() mutable {
2629         // 5.1. If all the following conditions hold:
2630         //      - mediaKeys is not null,
2631         //      - the CDM instance represented by mediaKeys is already in use by another media element
2632         //      - the user agent is unable to use it with this element
2633         //      then let this object's attaching media keys value be false and reject promise with a QuotaExceededError.
2634         // FIXME: ^
2635
2636         // 5.2. If the mediaKeys attribute is not null, run the following steps:
2637         if (m_mediaKeys) {
2638             // 5.2.1. If the user agent or CDM do not support removing the association, let this object's attaching media keys value be false and reject promise with a NotSupportedError.
2639             // 5.2.2. If the association cannot currently be removed, let this object's attaching media keys value be false and reject promise with an InvalidStateError.
2640             // 5.2.3. Stop using the CDM instance represented by the mediaKeys attribute to decrypt media data and remove the association with the media element.
2641             // 5.2.4. If the preceding step failed, let this object's attaching media keys value be false and reject promise with the appropriate error name.
2642             // FIXME: ^
2643
2644             m_mediaKeys->detachCDMClient(*this);
2645             if (m_player)
2646                 m_player->cdmInstanceDetached(m_mediaKeys->cdmInstance());
2647         }
2648
2649         // 5.3. If mediaKeys is not null, run the following steps:
2650         if (mediaKeys) {
2651             // 5.3.1. Associate the CDM instance represented by mediaKeys with the media element for decrypting media data.
2652             mediaKeys->attachCDMClient(*this);
2653             if (m_player)
2654                 m_player->cdmInstanceAttached(mediaKeys->cdmInstance());
2655
2656             // 5.3.2. If the preceding step failed, run the following steps:
2657             //   5.3.2.1. Set the mediaKeys attribute to null.
2658             //   5.3.2.2. Let this object's attaching media keys value be false.
2659             //   5.3.2.3. Reject promise with a new DOMException whose name is the appropriate error name.
2660             // FIXME: ^
2661
2662             // 5.3.3. Queue a task to run the Attempt to Resume Playback If Necessary algorithm on the media element.
2663             m_encryptedMediaQueue.enqueueTask([this] {
2664                 attemptToResumePlaybackIfNecessary();
2665             });
2666         }
2667
2668         // 5.4. Set the mediaKeys attribute to mediaKeys.
2669         // 5.5. Let this object's attaching media keys value be false.
2670         // 5.6. Resolve promise.
2671         m_mediaKeys = WTFMove(mediaKeys);
2672         m_attachingMediaKeys = false;
2673         promise->resolve();
2674     });
2675
2676     // 6. Return promise.
2677 }
2678
2679 void HTMLMediaElement::mediaPlayerInitializationDataEncountered(const String& initDataType, RefPtr<ArrayBuffer>&& initData)
2680 {
2681     // https://w3c.github.io/encrypted-media/#initdata-encountered
2682     // W3C Editor's Draft 23 June 2017
2683
2684     // 1. Let the media element be the specified HTMLMediaElement object.
2685     // 2. Let initDataType be the empty string.
2686     // 3. Let initData be null.
2687     // 4. If the media data is CORS-same-origin and not mixed content, run the following steps:
2688     //   4.1. Let initDataType be the string representing the Initialization Data Type of the Initialization Data.
2689     //   4.2. Let initData be the Initialization Data.
2690     // FIXME: ^
2691
2692     // 5. Queue a task to create an event named encrypted that does not bubble and is not cancellable using the
2693     //    MediaEncryptedEvent interface with its type attribute set to encrypted and its isTrusted attribute
2694     //    initialized to true, and dispatch it at the media element.
2695     //    The event interface MediaEncryptedEvent has:
2696     //      initDataType = initDataType
2697     //      initData = initData
2698     MediaEncryptedEventInit initializer { initDataType, WTFMove(initData) };
2699     m_asyncEventQueue.enqueueEvent(MediaEncryptedEvent::create(eventNames().encryptedEvent, initializer, Event::IsTrusted::Yes));
2700 }
2701
2702 void HTMLMediaElement::attemptToDecrypt()
2703 {
2704     // https://w3c.github.io/encrypted-media/#attempt-to-decrypt
2705     // W3C Editor's Draft 23 June 2017
2706
2707     // 1. Let the media element be the specified HTMLMediaElement object.
2708     // 2. If the media element's encrypted block queue is empty, abort these steps.
2709     // FIXME: ^
2710
2711     // 3. If the media element's mediaKeys attribute is not null, run the following steps:
2712     if (m_mediaKeys) {
2713         // 3.1. Let media keys be the MediaKeys object referenced by that attribute.
2714         // 3.2. Let cdm be the CDM instance represented by media keys's cdm instance value.
2715         auto& cdmInstance = m_mediaKeys->cdmInstance();
2716
2717         // 3.3. If cdm is no longer usable for any reason, run the following steps:
2718         //   3.3.1. Run the media data is corrupted steps of the resource fetch algorithm.
2719         //   3.3.2. Run the CDM Unavailable algorithm on media keys.
2720         //   3.3.3. Abort these steps.
2721         // FIXME: ^
2722
2723         // 3.4. If there is at least one MediaKeySession created by the media keys that is not closed, run the following steps:
2724         if (m_mediaKeys->hasOpenSessions()) {
2725             // Continued in MediaPlayer::attemptToDecryptWithInstance().
2726             if (m_player)
2727                 m_player->attemptToDecryptWithInstance(cdmInstance);
2728         }
2729     }
2730
2731     // 4. Set the media element's decryption blocked waiting for key value to true.
2732     // FIXME: ^
2733 }
2734
2735 void HTMLMediaElement::attemptToResumePlaybackIfNecessary()
2736 {
2737     // https://w3c.github.io/encrypted-media/#resume-playback
2738     // W3C Editor's Draft 23 June 2017
2739
2740     // 1. Let the media element be the specified HTMLMediaElement object.
2741     // 2. If the media element's playback blocked waiting for key is false, abort these steps.
2742     // FIXME: ^
2743
2744     // 3. Run the Attempt to Decrypt algorithm on the media element.
2745     attemptToDecrypt();
2746
2747     // 4. If the user agent can advance the current playback position in the direction of playback:
2748     //   4.1. Set the media element's decryption blocked waiting for key value to false.
2749     //   4.2. Set the media element's playback blocked waiting for key value to false.
2750     //   4.3. Set the media element's readyState value to HAVE_CURRENT_DATA, HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA as appropriate.
2751     // FIXME: ^
2752 }
2753
2754 void HTMLMediaElement::cdmClientAttemptToResumePlaybackIfNecessary()
2755 {
2756     attemptToResumePlaybackIfNecessary();
2757 }
2758
2759 #endif // ENABLE(ENCRYPTED_MEDIA)
2760
2761 void HTMLMediaElement::progressEventTimerFired()
2762 {
2763     ASSERT(m_player);
2764     if (m_networkState != NETWORK_LOADING)
2765         return;
2766
2767     double time = monotonicallyIncreasingTime();
2768     double timedelta = time - m_previousProgressTime;
2769
2770     if (m_player->didLoadingProgress()) {
2771         scheduleEvent(eventNames().progressEvent);
2772         m_previousProgressTime = time;
2773         m_sentStalledEvent = false;
2774         updateRenderer();
2775         if (hasMediaControls())
2776             mediaControls()->bufferingProgressed();
2777     } else if (timedelta > 3.0 && !m_sentStalledEvent) {
2778         scheduleEvent(eventNames().stalledEvent);
2779         m_sentStalledEvent = true;
2780         setShouldDelayLoadEvent(false);
2781     }
2782 }
2783
2784 void HTMLMediaElement::rewind(double timeDelta)
2785 {
2786     setCurrentTime(std::max(currentMediaTime() - MediaTime::createWithDouble(timeDelta), minTimeSeekable()));
2787 }
2788
2789 void HTMLMediaElement::returnToRealtime()
2790 {
2791     setCurrentTime(maxTimeSeekable());
2792 }
2793
2794 void HTMLMediaElement::addPlayedRange(const MediaTime& start, const MediaTime& end)
2795 {
2796     DEBUG_LOG(LOGIDENTIFIER, "[", start, ", ", end, "]");
2797     if (!m_playedTimeRanges)
2798         m_playedTimeRanges = TimeRanges::create();
2799     m_playedTimeRanges->ranges().add(start, end);
2800 }
2801
2802 bool HTMLMediaElement::supportsScanning() const
2803 {
2804     return m_player ? m_player->supportsScanning() : false;
2805 }
2806
2807 void HTMLMediaElement::prepareToPlay()
2808 {
2809     INFO_LOG(LOGIDENTIFIER);
2810     if (m_havePreparedToPlay)
2811         return;
2812     m_havePreparedToPlay = true;
2813     if (m_player)
2814         m_player->prepareToPlay();
2815 }
2816
2817 void HTMLMediaElement::fastSeek(double time)
2818 {
2819     fastSeek(MediaTime::createWithDouble(time));
2820 }
2821
2822 void HTMLMediaElement::fastSeek(const MediaTime& time)
2823 {
2824     INFO_LOG(LOGIDENTIFIER, time);
2825     // 4.7.10.9 Seeking
2826     // 9. If the approximate-for-speed flag is set, adjust the new playback position to a value that will
2827     // allow for playback to resume promptly. If new playback position before this step is before current
2828     // playback position, then the adjusted new playback position must also be before the current playback
2829     // position. Similarly, if the new playback position before this step is after current playback position,
2830     // then the adjusted new playback position must also be after the current playback position.
2831     refreshCachedTime();
2832
2833     MediaTime delta = time - currentMediaTime();
2834     MediaTime negativeTolerance = delta < MediaTime::zeroTime() ? MediaTime::positiveInfiniteTime() : delta;
2835     seekWithTolerance(time, negativeTolerance, MediaTime::zeroTime(), true);
2836 }
2837
2838 void HTMLMediaElement::seek(const MediaTime& time)
2839 {
2840     INFO_LOG(LOGIDENTIFIER, time);
2841     seekWithTolerance(time, MediaTime::zeroTime(), MediaTime::zeroTime(), true);
2842 }
2843
2844 void HTMLMediaElement::seekInternal(const MediaTime& time)
2845 {
2846     INFO_LOG(LOGIDENTIFIER, time);
2847     seekWithTolerance(time, MediaTime::zeroTime(), MediaTime::zeroTime(), false);
2848 }
2849
2850 void HTMLMediaElement::seekWithTolerance(const MediaTime& inTime, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance, bool fromDOM)
2851 {
2852     // 4.8.10.9 Seeking
2853     MediaTime time = inTime;
2854
2855     // 1 - Set the media element's show poster flag to false.
2856     setDisplayMode(Video);
2857
2858     // 2 - If the media element's readyState is HAVE_NOTHING, abort these steps.
2859     if (m_readyState == HAVE_NOTHING || !m_player)
2860         return;
2861
2862     // If the media engine has been told to postpone loading data, let it go ahead now.
2863     if (m_preload < MediaPlayer::Auto && m_readyState < HAVE_FUTURE_DATA)
2864         prepareToPlay();
2865
2866     // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
2867     refreshCachedTime();
2868     MediaTime now = currentMediaTime();
2869
2870     // 3 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
2871     // already running. Abort that other instance of the algorithm without waiting for the step that
2872     // it is running to complete.
2873     if (m_seekTaskQueue.hasPendingTasks()) {
2874         INFO_LOG(LOGIDENTIFIER, "cancelling pending seeks");
2875         m_seekTaskQueue.cancelAllTasks();
2876         if (m_pendingSeek) {
2877             now = m_pendingSeek->now;
2878             m_pendingSeek = nullptr;
2879         }
2880         m_pendingSeekType = NoSeek;
2881     }
2882
2883     // 4 - Set the seeking IDL attribute to true.
2884     // The flag will be cleared when the engine tells us the time has actually changed.
2885     m_seeking = true;
2886     if (m_playing) {
2887         if (m_lastSeekTime < now)
2888             addPlayedRange(m_lastSeekTime, now);
2889     }
2890     m_lastSeekTime = time;
2891
2892     // 5 - If the seek was in response to a DOM method call or setting of an IDL attribute, then continue
2893     // the script. The remainder of these steps must be run asynchronously.
2894     m_pendingSeek = std::make_unique<PendingSeek>(now, time, negativeTolerance, positiveTolerance);
2895     if (fromDOM) {
2896         INFO_LOG(LOGIDENTIFIER, "enqueuing seek from ", now, " to ", time);
2897         m_seekTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::seekTask, this));
2898     } else
2899         seekTask();
2900
2901     if (processingUserGestureForMedia())
2902         m_mediaSession->removeBehaviorRestriction(MediaElementSession::RequireUserGestureToControlControlsManager);
2903 }
2904
2905 void HTMLMediaElement::seekTask()
2906 {
2907     INFO_LOG(LOGIDENTIFIER);
2908
2909     if (!m_player) {
2910         clearSeeking();
2911         return;
2912     }
2913
2914     ASSERT(m_pendingSeek);
2915     MediaTime now = m_pendingSeek->now;
2916     MediaTime time = m_pendingSeek->targetTime;
2917     MediaTime negativeTolerance = m_pendingSeek->negativeTolerance;
2918     MediaTime positiveTolerance = m_pendingSeek->positiveTolerance;
2919     m_pendingSeek = nullptr;
2920
2921     ASSERT(negativeTolerance >= MediaTime::zeroTime());
2922
2923     // 6 - If the new playback position is later than the end of the media resource, then let it be the end
2924     // of the media resource instead.
2925     time = std::min(time, durationMediaTime());
2926
2927     // 7 - If the new playback position is less than the earliest possible position, let it be that position instead.
2928     MediaTime earliestTime = m_player->startTime();
2929     time = std::max(time, earliestTime);
2930
2931     // Ask the media engine for the time value in the movie's time scale before comparing with current time. This
2932     // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's
2933     // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
2934     // not generate a timechanged callback. This means m_seeking will never be cleared and we will never
2935     // fire a 'seeked' event.
2936     if (willLog(WTFLogLevelDebug)) {
2937         MediaTime mediaTime = m_player->mediaTimeForTimeValue(time);
2938         if (time != mediaTime)
2939             DEBUG_LOG(LOGIDENTIFIER, time, " media timeline equivalent is ", mediaTime);
2940     }
2941
2942     time = m_player->mediaTimeForTimeValue(time);
2943
2944     // 8 - If the (possibly now changed) new playback position is not in one of the ranges given in the
2945     // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute
2946     // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
2947     // attribute then set the seeking IDL attribute to false and abort these steps.
2948     RefPtr<TimeRanges> seekableRanges = seekable();
2949     bool noSeekRequired = !seekableRanges->length();
2950
2951     // Short circuit seeking to the current time by just firing the events if no seek is required.
2952     // Don't skip calling the media engine if 1) we are in poster mode (because a seek should always cancel
2953     // poster display), or 2) if there is a pending fast seek, or 3) if this seek is not an exact seek
2954     SeekType thisSeekType = (negativeTolerance == MediaTime::zeroTime() && positiveTolerance == MediaTime::zeroTime()) ? Precise : Fast;
2955     if (!noSeekRequired && time == now && thisSeekType == Precise && m_pendingSeekType != Fast && displayMode() != Poster)
2956         noSeekRequired = true;
2957
2958 #if ENABLE(MEDIA_SOURCE)
2959     // Always notify the media engine of a seek if the source is not closed. This ensures that the source is
2960     // always in a flushed state when the 'seeking' event fires.
2961     if (m_mediaSource && !m_mediaSource->isClosed())
2962         noSeekRequired = false;
2963 #endif
2964
2965     if (noSeekRequired) {
2966         INFO_LOG(LOGIDENTIFIER, "seek to ", time, " ignored");
2967         if (time == now) {
2968             scheduleEvent(eventNames().seekingEvent);
2969             scheduleTimeupdateEvent(false);
2970             scheduleEvent(eventNames().seekedEvent);
2971         }
2972         clearSeeking();
2973         return;
2974     }
2975     time = seekableRanges->ranges().nearest(time);
2976
2977     m_sentEndEvent = false;
2978     m_lastSeekTime = time;
2979     m_pendingSeekType = thisSeekType;
2980     m_seeking = true;
2981
2982     // 10 - Queue a task to fire a simple event named seeking at the element.
2983     scheduleEvent(eventNames().seekingEvent);
2984
2985     // 11 - Set the current playback position to the given new playback position
2986     m_seekRequested = true;
2987     m_player->seekWithTolerance(time, negativeTolerance, positiveTolerance);
2988
2989     // 12 - Wait until the user agent has established whether or not the media data for the new playback
2990     // position is available, and, if it is, until it has decoded enough data to play back that position.
2991     // 13 - Await a stable state. The synchronous section consists of all the remaining steps of this algorithm.
2992 }
2993
2994 void HTMLMediaElement::clearSeeking()
2995 {
2996     m_seeking = false;
2997     m_seekRequested = false;
2998     m_pendingSeekType = NoSeek;
2999     invalidateCachedTime();
3000 }
3001
3002 void HTMLMediaElement::finishSeek()
3003 {
3004     // 4.8.10.9 Seeking
3005     // 14 - Set the seeking IDL attribute to false.
3006     clearSeeking();
3007
3008     INFO_LOG(LOGIDENTIFIER, "current time = ", currentMediaTime());
3009
3010     // 15 - Run the time maches on steps.
3011     // Handled by mediaPlayerTimeChanged().
3012
3013     // 16 - Queue a task to fire a simple event named timeupdate at the element.
3014     scheduleEvent(eventNames().timeupdateEvent);
3015
3016     // 17 - Queue a task to fire a simple event named seeked at the element.
3017     scheduleEvent(eventNames().seekedEvent);
3018
3019 #if ENABLE(MEDIA_SOURCE)
3020     if (m_mediaSource)
3021         m_mediaSource->monitorSourceBuffers();
3022 #endif
3023 }
3024
3025 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
3026 {
3027     return m_readyState;
3028 }
3029
3030 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
3031 {
3032     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
3033 }
3034
3035 bool HTMLMediaElement::hasAudio() const
3036 {
3037     return m_player ? m_player->hasAudio() : false;
3038 }
3039
3040 bool HTMLMediaElement::seeking() const
3041 {
3042     return m_seeking;
3043 }
3044
3045 void HTMLMediaElement::refreshCachedTime() const
3046 {
3047     if (!m_player)
3048         return;
3049
3050     m_cachedTime = m_player->currentTime();
3051     if (!m_cachedTime) {
3052         // Do not use m_cachedTime until the media engine returns a non-zero value because we can't
3053         // estimate current time until playback actually begins.
3054         invalidateCachedTime();
3055         return;
3056     }
3057
3058     m_clockTimeAtLastCachedTimeUpdate = monotonicallyIncreasingTime();
3059 }
3060
3061 void HTMLMediaElement::invalidateCachedTime() const
3062 {
3063     m_cachedTime = MediaTime::invalidTime();
3064     if (!m_player || !m_player->maximumDurationToCacheMediaTime())
3065         return;
3066
3067     // Don't try to cache movie time when playback first starts as the time reported by the engine
3068     // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
3069     // too early.
3070     static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
3071
3072     m_minimumClockTimeToUpdateCachedTime = monotonicallyIncreasingTime() + minimumTimePlayingBeforeCacheSnapshot;
3073 }
3074
3075 // playback state
3076 double HTMLMediaElement::currentTime() const
3077 {
3078     return currentMediaTime().toDouble();
3079 }
3080
3081 MediaTime HTMLMediaElement::currentMediaTime() const
3082 {
3083 #if LOG_CACHED_TIME_WARNINGS
3084     static const MediaTime minCachedDeltaForWarning = MediaTime::create(1, 100);
3085 #endif
3086
3087     if (!m_player)
3088         return MediaTime::zeroTime();
3089
3090     if (m_seeking) {
3091         INFO_LOG(LOGIDENTIFIER, "seeking, returning", m_lastSeekTime);
3092         return m_lastSeekTime;
3093     }
3094
3095     if (m_cachedTime.isValid() && m_paused) {
3096 #if LOG_CACHED_TIME_WARNINGS
3097         MediaTime delta = m_cachedTime - m_player->currentTime();
3098         if (delta > minCachedDeltaForWarning)
3099             WARNING_LOG(LOGIDENTIFIER, "cached time is ", delta, " seconds off of media time when paused");
3100 #endif
3101         return m_cachedTime;
3102     }
3103
3104     // Is it too soon use a cached time?
3105     double now = monotonicallyIncreasingTime();
3106     double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
3107
3108     if (maximumDurationToCacheMediaTime && m_cachedTime.isValid() && !m_paused && now > m_minimumClockTimeToUpdateCachedTime) {
3109         double clockDelta = now - m_clockTimeAtLastCachedTimeUpdate;
3110
3111         // Not too soon, use the cached time only if it hasn't expired.
3112         if (clockDelta < maximumDurationToCacheMediaTime) {
3113             MediaTime adjustedCacheTime = m_cachedTime + MediaTime::createWithDouble(effectivePlaybackRate() * clockDelta);
3114
3115 #if LOG_CACHED_TIME_WARNINGS
3116             MediaTime delta = adjustedCacheTime - m_player->currentTime();
3117             if (delta > minCachedDeltaForWarning)
3118                 WARNING_LOG(LOGIDENTIFIER, "cached time is ", delta, " seconds off of media time when playing");
3119 #endif
3120             return adjustedCacheTime;
3121         }
3122     }
3123
3124 #if LOG_CACHED_TIME_WARNINGS
3125     if (maximumDurationToCacheMediaTime && now > m_minimumClockTimeToUpdateCachedTime && m_cachedTime != MediaPlayer::invalidTime()) {
3126         double clockDelta = now - m_clockTimeAtLastCachedTimeUpdate;
3127         MediaTime delta = m_cachedTime + MediaTime::createWithDouble(effectivePlaybackRate() * clockDelta) - m_player->currentTime();
3128         WARNING_LOG(LOGIDENTIFIER, "cached time was ", delta, " seconds off of media time when it expired");
3129     }
3130 #endif
3131
3132     refreshCachedTime();
3133
3134     if (m_cachedTime.isInvalid())
3135         return MediaTime::zeroTime();
3136
3137     return m_cachedTime;
3138 }
3139
3140 void HTMLMediaElement::setCurrentTime(double time)
3141 {
3142     setCurrentTime(MediaTime::createWithDouble(time));
3143 }
3144
3145 void HTMLMediaElement::setCurrentTimeWithTolerance(double time, double toleranceBefore, double toleranceAfter)
3146 {
3147     seekWithTolerance(MediaTime::createWithDouble(time), MediaTime::createWithDouble(toleranceBefore), MediaTime::createWithDouble(toleranceAfter), true);
3148 }
3149
3150 void HTMLMediaElement::setCurrentTime(const MediaTime& time)
3151 {
3152     if (m_mediaController)
3153         return;
3154
3155     seekInternal(time);
3156 }
3157
3158 ExceptionOr<void> HTMLMediaElement::setCurrentTimeForBindings(double time)
3159 {
3160     if (m_mediaController)
3161         return Exception { InvalidStateError };
3162     seek(MediaTime::createWithDouble(time));
3163     return { };
3164 }
3165
3166 double HTMLMediaElement::duration() const
3167 {
3168     return durationMediaTime().toDouble();
3169 }
3170
3171 MediaTime HTMLMediaElement::durationMediaTime() const
3172 {
3173     if (m_player && m_readyState >= HAVE_METADATA)
3174         return m_player->duration();
3175
3176     return MediaTime::invalidTime();
3177 }
3178
3179 bool HTMLMediaElement::paused() const
3180 {
3181     // As of this writing, JavaScript garbage collection calls this function directly. In the past
3182     // we had problems where this was called on an object after a bad cast. The assertion below
3183     // made our regression test detect the problem, so we should keep it because of that. But note
3184     // that the value of the assertion relies on the compiler not being smart enough to know that
3185     // isHTMLUnknownElement is guaranteed to return false for an HTMLMediaElement.
3186     ASSERT(!isHTMLUnknownElement());
3187
3188     return m_paused;
3189 }
3190
3191 double HTMLMediaElement::defaultPlaybackRate() const
3192 {
3193 #if ENABLE(MEDIA_STREAM)
3194     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3195     // "defaultPlaybackRate" - On setting: ignored. On getting: return 1.0
3196     // A MediaStream is not seekable. Therefore, this attribute must always have the
3197     // value 1.0 and any attempt to alter it must be ignored. Note that this also means
3198     // that the ratechange event will not fire.
3199     if (m_mediaStreamSrcObject)
3200         return 1;
3201 #endif
3202
3203     return m_defaultPlaybackRate;
3204 }
3205
3206 void HTMLMediaElement::setDefaultPlaybackRate(double rate)
3207 {
3208 #if ENABLE(MEDIA_STREAM)
3209     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3210     // "defaultPlaybackRate" - On setting: ignored. On getting: return 1.0
3211     // A MediaStream is not seekable. Therefore, this attribute must always have the
3212     // value 1.0 and any attempt to alter it must be ignored. Note that this also means
3213     // that the ratechange event will not fire.
3214     if (m_mediaStreamSrcObject)
3215         return;
3216 #endif
3217
3218     if (m_defaultPlaybackRate == rate)
3219         return;
3220
3221     ALWAYS_LOG(LOGIDENTIFIER, rate);
3222     m_defaultPlaybackRate = rate;
3223     scheduleEvent(eventNames().ratechangeEvent);
3224 }
3225
3226 double HTMLMediaElement::effectivePlaybackRate() const
3227 {
3228     return m_mediaController ? m_mediaController->playbackRate() : m_reportedPlaybackRate;
3229 }
3230
3231 double HTMLMediaElement::requestedPlaybackRate() const
3232 {
3233     return m_mediaController ? m_mediaController->playbackRate() : m_requestedPlaybackRate;
3234 }
3235
3236 double HTMLMediaElement::playbackRate() const
3237 {
3238 #if ENABLE(MEDIA_STREAM)
3239     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3240     // "playbackRate" - A MediaStream is not seekable. Therefore, this attribute must always
3241     // have the value 1.0 and any attempt to alter it must be ignored. Note that this also
3242     // means that the ratechange event will not fire.
3243     if (m_mediaStreamSrcObject)
3244         return 1;
3245 #endif
3246
3247     return m_requestedPlaybackRate;
3248 }
3249
3250 void HTMLMediaElement::setPlaybackRate(double rate)
3251 {
3252     ALWAYS_LOG(LOGIDENTIFIER, rate);
3253
3254 #if ENABLE(MEDIA_STREAM)
3255     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3256     // "playbackRate" - A MediaStream is not seekable. Therefore, this attribute must always
3257     // have the value 1.0 and any attempt to alter it must be ignored. Note that this also
3258     // means that the ratechange event will not fire.
3259     if (m_mediaStreamSrcObject)
3260         return;
3261 #endif
3262
3263     if (m_player && potentiallyPlaying() && m_player->rate() != rate && !m_mediaController)
3264         m_player->setRate(rate);
3265
3266     if (m_requestedPlaybackRate != rate) {
3267         m_reportedPlaybackRate = m_requestedPlaybackRate = rate;
3268         invalidateCachedTime();
3269         scheduleEvent(eventNames().ratechangeEvent);
3270     }
3271 }
3272
3273 void HTMLMediaElement::updatePlaybackRate()
3274 {
3275     double requestedRate = requestedPlaybackRate();
3276     if (m_player && potentiallyPlaying() && m_player->rate() != requestedRate)
3277         m_player->setRate(requestedRate);
3278 }
3279
3280 bool HTMLMediaElement::webkitPreservesPitch() const
3281 {
3282     return m_webkitPreservesPitch;
3283 }
3284
3285 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
3286 {
3287     INFO_LOG(LOGIDENTIFIER, preservesPitch);
3288
3289     m_webkitPreservesPitch = preservesPitch;
3290
3291     if (!m_player)
3292         return;
3293
3294     m_player->setPreservesPitch(preservesPitch);
3295 }
3296
3297 bool HTMLMediaElement::ended() const
3298 {
3299 #if ENABLE(MEDIA_STREAM)
3300     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3301     // When the MediaStream state moves from the active to the inactive state, the User Agent
3302     // must raise an ended event on the HTMLMediaElement and set its ended attribute to true.
3303     if (m_mediaStreamSrcObject && m_player && m_player->ended())
3304         return true;
3305 #endif
3306
3307     // 4.8.10.8 Playing the media resource
3308     // The ended attribute must return true if the media element has ended
3309     // playback and the direction of playback is forwards, and false otherwise.
3310     return endedPlayback() && requestedPlaybackRate() > 0;
3311 }
3312
3313 bool HTMLMediaElement::autoplay() const
3314 {
3315     return hasAttributeWithoutSynchronization(autoplayAttr);
3316 }
3317
3318 String HTMLMediaElement::preload() const
3319 {
3320 #if ENABLE(MEDIA_STREAM)
3321     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3322     // "preload" - On getting: none. On setting: ignored.
3323     if (m_mediaStreamSrcObject)
3324         return ASCIILiteral("none");
3325 #endif
3326
3327     switch (m_preload) {
3328     case MediaPlayer::None:
3329         return ASCIILiteral("none");
3330     case MediaPlayer::MetaData:
3331         return ASCIILiteral("metadata");
3332     case MediaPlayer::Auto:
3333         return ASCIILiteral("auto");
3334     }
3335
3336     ASSERT_NOT_REACHED();
3337     return String();
3338 }
3339
3340 void HTMLMediaElement::setPreload(const String& preload)
3341 {
3342     INFO_LOG(LOGIDENTIFIER, preload);
3343 #if ENABLE(MEDIA_STREAM)
3344     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3345     // "preload" - On getting: none. On setting: ignored.
3346     if (m_mediaStreamSrcObject)
3347         return;
3348 #endif
3349
3350     setAttributeWithoutSynchronization(preloadAttr, preload);
3351 }
3352
3353 void HTMLMediaElement::play(DOMPromiseDeferred<void>&& promise)
3354 {
3355     ALWAYS_LOG(LOGIDENTIFIER);
3356
3357     auto success = m_mediaSession->playbackPermitted(*this);
3358     if (!success) {
3359         if (success.value() == MediaPlaybackDenialReason::UserGestureRequired)
3360             setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
3361         promise.reject(NotAllowedError);
3362         return;
3363     }
3364
3365     if (m_error && m_error->code() == MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED) {
3366         promise.reject(NotSupportedError, "The operation is not supported.");
3367         return;
3368     }
3369
3370     if (processingUserGestureForMedia())
3371         removeBehaviorsRestrictionsAfterFirstUserGesture();
3372
3373     if (!playInternal()) {
3374         promise.reject(NotAllowedError);
3375         return;
3376     }
3377
3378     m_pendingPlayPromises.append(WTFMove(promise));
3379 }
3380
3381 void HTMLMediaElement::play()
3382 {
3383     ALWAYS_LOG(LOGIDENTIFIER);
3384
3385     auto success = m_mediaSession->playbackPermitted(*this);
3386     if (!success) {
3387         if (success.value() == MediaPlaybackDenialReason::UserGestureRequired)
3388             setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
3389         return;
3390     }
3391     if (processingUserGestureForMedia())
3392         removeBehaviorsRestrictionsAfterFirstUserGesture();
3393
3394     playInternal();
3395 }
3396
3397 bool HTMLMediaElement::playInternal()
3398 {
3399     ALWAYS_LOG(LOGIDENTIFIER);
3400
3401     if (!m_mediaSession->clientWillBeginPlayback()) {
3402         ALWAYS_LOG(LOGIDENTIFIER, "  returning because of interruption");
3403         return true; // Treat as success because we will begin playback on cessation of the interruption.
3404     }
3405
3406     // 4.8.10.9. Playing the media resource
3407     if (!m_player || m_networkState == NETWORK_EMPTY)
3408         prepareForLoad();
3409
3410     if (endedPlayback())
3411         seekInternal(MediaTime::zeroTime());
3412
3413     if (m_mediaController)
3414         m_mediaController->bringElementUpToSpeed(*this);
3415
3416     if (m_paused) {
3417         m_paused = false;
3418         invalidateCachedTime();
3419         m_playbackStartedTime = currentMediaTime().toDouble();
3420         scheduleEvent(eventNames().playEvent);
3421
3422         if (m_readyState <= HAVE_CURRENT_DATA)
3423             scheduleEvent(eventNames().waitingEvent);
3424         else if (m_readyState >= HAVE_FUTURE_DATA)
3425             scheduleNotifyAboutPlaying();
3426
3427 #if ENABLE(MEDIA_SESSION)
3428         // 6.3 Activating a media session from a media element
3429         // When the play() method is invoked, the paused attribute is true, and the readyState attribute has the value
3430         // HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA, then
3431         // 1. Let media session be the value of the current media session.
3432         // 2. If we are not currently in media session's list of active participating media elements then append
3433         //    ourselves to this list.
3434         // 3. Let activated be the result of running the media session invocation algorithm for media session.
3435         // 4. If activated is failure, pause ourselves.
3436         if (m_readyState == HAVE_ENOUGH_DATA || m_readyState == HAVE_FUTURE_DATA) {
3437             if (m_session) {
3438                 m_session->addActiveMediaElement(*this);
3439
3440                 if (m_session->kind() == MediaSessionKind::Content) {
3441                     if (Page* page = document().page())
3442                         page->chrome().client().focusedContentMediaElementDidChange(m_elementID);
3443                 }
3444
3445                 if (!m_session->invoke()) {
3446                     pause();
3447                     return false;
3448                 }
3449             }
3450         }
3451 #endif
3452     } else if (m_readyState >= HAVE_FUTURE_DATA)
3453         scheduleResolvePendingPlayPromises();
3454
3455     if (processingUserGestureForMedia()) {
3456         if (m_playbackWithoutUserGesture == PlaybackWithoutUserGesture::Prevented) {
3457             handleAutoplayEvent(AutoplayEvent::DidPlayMediaPreventedFromPlaying);
3458             setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
3459         }
3460     } else
3461         setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Started);
3462
3463     m_autoplaying = false;
3464     updatePlayState();
3465
3466     return true;
3467 }
3468
3469 void HTMLMediaElement::pause()
3470 {
3471     ALWAYS_LOG(LOGIDENTIFIER);
3472
3473     m_temporarilyAllowingInlinePlaybackAfterFullscreen = false;
3474
3475     if (!m_mediaSession->playbackPermitted(*this))
3476         return;
3477
3478     if (processingUserGestureForMedia())
3479         removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::RequireUserGestureToControlControlsManager);
3480
3481     pauseInternal();
3482 }
3483
3484
3485 void HTMLMediaElement::pauseInternal()
3486 {
3487     ALWAYS_LOG(LOGIDENTIFIER);
3488
3489     if (!m_mediaSession->clientWillPausePlayback()) {
3490         ALWAYS_LOG(LOGIDENTIFIER, "  returning because of interruption");
3491         return;
3492     }
3493
3494     // 4.8.10.9. Playing the media resource
3495     if (!m_player || m_networkState == NETWORK_EMPTY) {
3496         // Unless the restriction on media requiring user action has been lifted
3497         // don't trigger loading if a script calls pause().
3498         if (!m_mediaSession->playbackPermitted(*this))
3499             return;
3500         prepareForLoad();
3501     }
3502
3503     m_autoplaying = false;
3504
3505     if (processingUserGestureForMedia())
3506         userDidInterfereWithAutoplay();
3507
3508     setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
3509
3510     if (!m_paused) {
3511         m_paused = true;
3512         scheduleTimeupdateEvent(false);
3513         scheduleEvent(eventNames().pauseEvent);
3514         m_promiseTaskQueue.enqueueTask([this]() {
3515             rejectPendingPlayPromises(DOMException::create(AbortError));
3516         });
3517         if (MemoryPressureHandler::singleton().isUnderMemoryPressure())
3518             purgeBufferedDataIfPossible();
3519     }
3520
3521     updatePlayState();
3522 }
3523
3524 #if ENABLE(MEDIA_SOURCE)
3525
3526 void HTMLMediaElement::detachMediaSource()
3527 {
3528     if (!m_mediaSource)
3529         return;
3530
3531     m_mediaSource->detachFromElement(*this);
3532     m_mediaSource = nullptr;
3533 }
3534
3535 #endif
3536
3537 bool HTMLMediaElement::loop() const
3538 {
3539     return hasAttributeWithoutSynchronization(loopAttr);
3540 }
3541
3542 void HTMLMediaElement::setLoop(bool b)
3543 {
3544     INFO_LOG(LOGIDENTIFIER, b);
3545     setBooleanAttribute(loopAttr, b);
3546 }
3547
3548 bool HTMLMediaElement::controls() const
3549 {
3550     RefPtr<Frame> frame = document().frame();
3551
3552     // always show controls when scripting is disabled
3553     if (frame && !frame->script().canExecuteScripts(NotAboutToExecuteScript))
3554         return true;
3555
3556     return hasAttributeWithoutSynchronization(controlsAttr);
3557 }
3558
3559 void HTMLMediaElement::setControls(bool b)
3560 {
3561     INFO_LOG(LOGIDENTIFIER, b);
3562     setBooleanAttribute(controlsAttr, b);
3563 }
3564
3565 double HTMLMediaElement::volume() const
3566 {
3567     return m_volume;
3568 }
3569
3570 ExceptionOr<void> HTMLMediaElement::setVolume(double volume)
3571 {
3572     INFO_LOG(LOGIDENTIFIER, volume);
3573
3574     if (!(volume >= 0 && volume <= 1))
3575         return Exception { IndexSizeError };
3576
3577 #if !PLATFORM(IOS)
3578     if (m_volume == volume)
3579         return { };
3580
3581     if (volume && processingUserGestureForMedia())
3582         removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager);
3583
3584     m_volume = volume;
3585     m_volumeInitialized = true;
3586     updateVolume();
3587     scheduleEvent(eventNames().volumechangeEvent);
3588
3589     if (isPlaying() && !m_mediaSession->playbackPermitted(*this)) {
3590         pauseInternal();
3591         setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
3592     }
3593 #endif
3594     return { };
3595 }
3596
3597 bool HTMLMediaElement::muted() const
3598 {
3599     return m_explicitlyMuted ? m_muted : hasAttributeWithoutSynchronization(mutedAttr);
3600 }
3601
3602 void HTMLMediaElement::setMuted(bool muted)
3603 {
3604     INFO_LOG(LOGIDENTIFIER, muted);
3605
3606     bool mutedStateChanged = m_muted != muted;
3607     if (mutedStateChanged || !m_explicitlyMuted) {
3608         if (processingUserGestureForMedia()) {
3609             removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager);
3610
3611             if (hasAudio() && muted)
3612                 userDidInterfereWithAutoplay();
3613         }
3614
3615         m_muted = muted;
3616         m_explicitlyMuted = true;
3617
3618         // Avoid recursion when the player reports volume changes.
3619         if (!processingMediaPlayerCallback()) {
3620             if (m_player) {
3621                 m_player->setMuted(effectiveMuted());
3622                 if (hasMediaControls())
3623                     mediaControls()->changedMute();
3624             }
3625         }
3626
3627         if (mutedStateChanged)
3628             scheduleEvent(eventNames().volumechangeEvent);
3629
3630         updateShouldPlay();
3631
3632 #if ENABLE(MEDIA_SESSION)
3633         document().updateIsPlayingMedia(m_elementID);
3634 #else
3635         document().updateIsPlayingMedia();
3636 #endif
3637
3638 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
3639         updateMediaState(UpdateState::Asynchronously);
3640 #endif
3641         m_mediaSession->canProduceAudioChanged();
3642     }
3643
3644     scheduleUpdatePlaybackControlsManager();
3645 }
3646
3647 #if USE(AUDIO_SESSION) && PLATFORM(MAC)
3648 void HTMLMediaElement::hardwareMutedStateDidChange(AudioSession* session)
3649 {
3650     if (!session->isMuted())
3651         return;
3652
3653     if (!hasAudio())
3654         return;
3655
3656     if (effectiveMuted() || !volume())
3657         return;
3658
3659     userDidInterfereWithAutoplay();
3660 }
3661 #endif
3662
3663 void HTMLMediaElement::togglePlayState()
3664 {
3665     INFO_LOG(LOGIDENTIFIER, "canPlay() is ", canPlay());
3666
3667     // We can safely call the internal play/pause methods, which don't check restrictions, because
3668     // this method is only called from the built-in media controller
3669     if (canPlay()) {
3670         updatePlaybackRate();
3671         playInternal();
3672     } else
3673         pauseInternal();
3674 }
3675
3676 void HTMLMediaElement::beginScrubbing()
3677 {
3678     INFO_LOG(LOGIDENTIFIER, "paused() is ", paused());
3679
3680     if (!paused()) {
3681         if (ended()) {
3682             // Because a media element stays in non-paused state when it reaches end, playback resumes
3683             // when the slider is dragged from the end to another position unless we pause first. Do
3684             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
3685             pause();
3686         } else {
3687             // Not at the end but we still want to pause playback so the media engine doesn't try to
3688             // continue playing during scrubbing. Pause without generating an event as we will
3689             // unpause after scrubbing finishes.
3690             setPausedInternal(true);
3691         }
3692     }
3693
3694     m_mediaSession->removeBehaviorRestriction(MediaElementSession::RequireUserGestureToControlControlsManager);
3695 }
3696
3697 void HTMLMediaElement::endScrubbing()
3698 {
3699     INFO_LOG(LOGIDENTIFIER, "m_pausedInternal is", m_pausedInternal);
3700
3701     if (m_pausedInternal)
3702         setPausedInternal(false);
3703 }
3704
3705 void HTMLMediaElement::beginScanning(ScanDirection direction)
3706 {
3707     m_scanType = supportsScanning() ? Scan : Seek;
3708     m_scanDirection = direction;
3709
3710     if (m_scanType == Seek) {
3711         // Scanning by seeking requires the video to be paused during scanning.
3712         m_actionAfterScan = paused() ? Nothing : Play;
3713         pause();
3714     } else {
3715         // Scanning by scanning requires the video to be playing during scanninging.
3716         m_actionAfterScan = paused() ? Pause : Nothing;
3717         play();
3718         setPlaybackRate(nextScanRate());
3719     }
3720
3721     m_scanTimer.start(0_s, m_scanType == Seek ? SeekRepeatDelay : ScanRepeatDelay);
3722 }
3723
3724 void HTMLMediaElement::endScanning()
3725 {
3726     if (m_scanType == Scan)
3727         setPlaybackRate(defaultPlaybackRate());
3728
3729     if (m_actionAfterScan == Play)
3730         play();
3731     else if (m_actionAfterScan == Pause)
3732         pause();
3733
3734     if (m_scanTimer.isActive())
3735         m_scanTimer.stop();
3736 }
3737
3738 double HTMLMediaElement::nextScanRate()
3739 {
3740     double rate = std::min(ScanMaximumRate, fabs(playbackRate() * 2));
3741     if (m_scanDirection == Backward)
3742         rate *= -1;
3743 #if PLATFORM(IOS)
3744     rate = std::min(std::max(rate, minFastReverseRate()), maxFastForwardRate());
3745 #endif
3746     return rate;
3747 }
3748
3749 void HTMLMediaElement::scanTimerFired()
3750 {
3751     if (m_scanType == Seek) {
3752         double seekTime = m_scanDirection == Forward ? SeekTime : -SeekTime;
3753         setCurrentTime(currentTime() + seekTime);
3754     } else
3755         setPlaybackRate(nextScanRate());
3756 }
3757
3758 // The spec says to fire periodic timeupdate events (those sent while playing) every
3759 // "15 to 250ms", we choose the slowest frequency
3760 static const Seconds maxTimeupdateEventFrequency { 250_ms };
3761
3762 void HTMLMediaElement::startPlaybackProgressTimer()
3763 {
3764     if (m_playbackProgressTimer.isActive())
3765         return;
3766
3767     m_previousProgressTime = monotonicallyIncreasingTime();
3768     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
3769 }
3770
3771 void HTMLMediaElement::playbackProgressTimerFired()
3772 {
3773     ASSERT(m_player);
3774
3775     if (m_fragmentEndTime.isValid() && currentMediaTime() >= m_fragmentEndTime && requestedPlaybackRate() > 0) {
3776         m_fragmentEndTime = MediaTime::invalidTime();
3777         if (!m_mediaController && !m_paused) {
3778             // changes paused to true and fires a simple event named pause at the media element.
3779             pauseInternal();
3780         }
3781     }
3782
3783     scheduleTimeupdateEvent(true);
3784
3785     if (!requestedPlaybackRate())
3786         return;
3787
3788     if (!m_paused && hasMediaControls())
3789         mediaControls()->playbackProgressed();
3790
3791 #if ENABLE(VIDEO_TRACK)
3792     updateActiveTextTrackCues(currentMediaTime());
3793 #endif
3794
3795 #if ENABLE(MEDIA_SOURCE)
3796     if (m_mediaSource)
3797         m_mediaSource->monitorSourceBuffers();
3798 #endif
3799
3800     if (!seeking() && m_playbackWithoutUserGesture == PlaybackWithoutUserGesture::Started && currentTime() - m_playbackWithoutUserGestureStartedTime->toDouble() > AutoplayInterferenceTimeThreshold) {
3801         handleAutoplayEvent(AutoplayEvent::DidAutoplayMediaPastThresholdWithoutUserInterference);
3802         setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
3803     }
3804 }
3805
3806 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
3807 {
3808     MonotonicTime now = MonotonicTime::now();
3809     Seconds timedelta = now - m_clockTimeAtLastUpdateEvent;
3810
3811     // throttle the periodic events
3812     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
3813         return;
3814
3815     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
3816     // event at a given time so filter here
3817     MediaTime movieTime = currentMediaTime();
3818     if (movieTime != m_lastTimeUpdateEventMovieTime) {
3819         scheduleEvent(eventNames().timeupdateEvent);
3820         m_clockTimeAtLastUpdateEvent = now;
3821         m_lastTimeUpdateEventMovieTime = movieTime;
3822     }
3823 }
3824
3825 bool HTMLMediaElement::canPlay() const
3826 {
3827     return paused() || ended() || m_readyState < HAVE_METADATA;
3828 }
3829
3830 double HTMLMediaElement::percentLoaded() const
3831 {
3832     if (!m_player)
3833         return 0;
3834     MediaTime duration = m_player->duration();
3835
3836     if (!duration || duration.isPositiveInfinite() || duration.isNegativeInfinite())
3837         return 0;
3838
3839     MediaTime buffered = MediaTime::zeroTime();
3840     bool ignored;
3841     std::unique_ptr<PlatformTimeRanges> timeRanges = m_player->buffered();
3842     for (unsigned i = 0; i < timeRanges->length(); ++i) {
3843         MediaTime start = timeRanges->start(i, ignored);
3844         MediaTime end = timeRanges->end(i, ignored);
3845         buffered += end - start;
3846     }
3847     return buffered.toDouble() / duration.toDouble();
3848 }
3849
3850 #if ENABLE(VIDEO_TRACK)
3851
3852 void HTMLMediaElement::mediaPlayerDidAddAudioTrack(AudioTrackPrivate& track)
3853 {
3854     if (isPlaying() && !m_mediaSession->playbackPermitted(*this)) {
3855         pauseInternal();
3856         setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
3857     }
3858
3859     addAudioTrack(AudioTrack::create(*this, track));
3860 }
3861
3862 void HTMLMediaElement::mediaPlayerDidAddTextTrack(InbandTextTrackPrivate& track)
3863 {
3864     // 4.8.10.12.2 Sourcing in-band text tracks
3865     // 1. Associate the relevant data with a new text track and its corresponding new TextTrack object.
3866     auto textTrack = InbandTextTrack::create(*ActiveDOMObject::scriptExecutionContext(), *this, track);
3867     textTrack->setMediaElement(this);
3868
3869     // 2. Set the new text track's kind, label, and language based on the semantics of the relevant data,
3870     // as defined by the relevant specification. If there is no label in that data, then the label must
3871     // be set to the empty string.
3872     // 3. Associate the text track list of cues with the rules for updating the text track rendering appropriate
3873     // for the format in question.
3874     // 4. If the new text track's kind is metadata, then set the text track in-band metadata track dispatch type
3875     // as follows, based on the type of the media resource:
3876     // 5. Populate the new text track's list of cues with the cues parsed so far, folllowing the guidelines for exposing
3877     // cues, and begin updating it dynamically as necessary.
3878     //   - Thess are all done by the media engine.
3879
3880     // 6. Set the new text track's readiness state to loaded.
3881     textTrack->setReadinessState(TextTrack::Loaded);
3882
3883     // 7. Set the new text track's mode to the mode consistent with the user's preferences and the requirements of
3884     // the relevant specification for the data.
3885     //  - This will happen in configureTextTracks()
3886     scheduleDelayedAction(ConfigureTextTracks);
3887
3888     // 8. Add the new text track to the media element's list of text tracks.
3889     // 9. Fire an event with the name addtrack, that does not bubble and is not cancelable, and that uses the TrackEvent
3890     // interface, with the track attribute initialized to the text track's TextTrack object, at the media element's
3891     // textTracks attribute's TextTrackList object.
3892     addTextTrack(WTFMove(textTrack));
3893 }
3894
3895 void HTMLMediaElement::mediaPlayerDidAddVideoTrack(VideoTrackPrivate& track)
3896 {
3897     addVideoTrack(VideoTrack::create(*this, track));
3898 }
3899
3900 void HTMLMediaElement::mediaPlayerDidRemoveAudioTrack(AudioTrackPrivate& track)
3901 {
3902     track.willBeRemoved();
3903 }
3904
3905 void HTMLMediaElement::mediaPlayerDidRemoveTextTrack(InbandTextTrackPrivate& track)
3906 {
3907     track.willBeRemoved();
3908 }
3909
3910 void HTMLMediaElement::mediaPlayerDidRemoveVideoTrack(VideoTrackPrivate& track)
3911 {
3912     track.willBeRemoved();
3913 }
3914
3915 void HTMLMediaElement::closeCaptionTracksChanged()
3916 {
3917     if (hasMediaControls())
3918         mediaControls()->closedCaptionTracksChanged();
3919 }
3920
3921 void HTMLMediaElement::addAudioTrack(Ref<AudioTrack>&& track)
3922 {
3923     audioTracks().append(WTFMove(track));
3924 }
3925
3926 void HTMLMediaElement::addTextTrack(Ref<TextTrack>&& track)
3927 {
3928     if (!m_requireCaptionPreferencesChangedCallbacks) {
3929         m_requireCaptionPreferencesChangedCallbacks = true;
3930         Document& document = this->document();
3931         document.registerForCaptionPreferencesChangedCallbacks(this);
3932         if (Page* page = document.page())
3933             m_captionDisplayMode = page->group().captionPreferences().captionDisplayMode();
3934     }
3935
3936     textTracks().append(WTFMove(track));
3937
3938     closeCaptionTracksChanged();
3939 }
3940
3941 void HTMLMediaElement::addVideoTrack(Ref<VideoTrack>&& track)
3942 {
3943     videoTracks().append(WTFMove(track));
3944 }
3945
3946 void HTMLMediaElement::removeAudioTrack(AudioTrack& track)
3947 {
3948     m_audioTracks->remove(track);
3949     track.clearClient();
3950 }
3951
3952 void HTMLMediaElement::removeTextTrack(TextTrack& track, bool scheduleEvent)
3953 {
3954     TrackDisplayUpdateScope scope { *this };
3955     if (auto* cues = track.cues())
3956         textTrackRemoveCues(track, *cues);
3957     track.clearClient();
3958     if (m_textTracks)
3959         m_textTracks->remove(track, scheduleEvent);
3960
3961     closeCaptionTracksChanged();
3962 }
3963
3964 void HTMLMediaElement::removeVideoTrack(VideoTrack& track)
3965 {
3966     m_videoTracks->remove(track);
3967     track.clearClient();
3968 }
3969
3970 void HTMLMediaElement::forgetResourceSpecificTracks()
3971 {
3972     while (m_audioTracks &&  m_audioTracks->length())
3973         removeAudioTrack(*m_audioTracks->lastItem());
3974
3975     if (m_textTracks) {
3976         TrackDisplayUpdateScope scope { *this };
3977         for (int i = m_textTracks->length() - 1; i >= 0; --i) {
3978             auto& track = *m_textTracks->item(i);
3979             if (track.trackType() == TextTrack::InBand)
3980                 removeTextTrack(track, false);
3981         }
3982     }
3983
3984     while (m_videoTracks &&  m_videoTracks->length())
3985         removeVideoTrack(*m_videoTracks->lastItem());
3986 }
3987
3988 ExceptionOr<TextTrack&> HTMLMediaElement::addTextTrack(const String& kind, const String& label, const String& language)
3989 {
3990     // 4.8.10.12.4 Text track API
3991     // The addTextTrack(kind, label, language) method of media elements, when invoked, must run the following steps:
3992
3993     // 1. If kind is not one of the following strings, then throw a SyntaxError exception and abort these steps
3994     if (!TextTrack::isValidKindKeyword(kind))
3995         return Exception { TypeError };
3996
3997     // 2. If the label argument was omitted, let label be the empty string.
3998     // 3. If the language argument was omitted, let language be the empty string.
3999     // 4. Create a new TextTrack object.
4000
4001     // 5. Create a new text track corresponding to the new object, and set its text track kind to kind, its text
4002     // track label to label, its text track language to language...
4003     auto track = TextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, kind, emptyString(), label, language);
4004     auto& trackReference = track.get();
4005
4006     // Note, due to side effects when changing track parameters, we have to
4007     // first append the track to the text track list.
4008
4009     // 6. Add the new text track to the media element's list of text tracks.
4010     addTextTrack(WTFMove(track));
4011
4012     // ... its text track readiness state to the text track loaded state ...
4013     trackReference.setReadinessState(TextTrack::Loaded);
4014
4015     // ... its text track mode to the text track hidden mode, and its text track list of cues to an empty list ...
4016     trackReference.setMode(TextTrack::Mode::Hidden);
4017
4018     return trackReference;
4019 }
4020
4021 AudioTrackList& HTMLMediaElement::audioTracks()
4022 {
4023     if (!m_audioTracks)
4024         m_audioTracks = AudioTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
4025
4026     return *m_audioTracks;
4027 }
4028
4029 TextTrackList& HTMLMediaElement::textTracks()
4030 {
4031     if (!m_textTracks)
4032         m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
4033
4034     return *m_textTracks;
4035 }
4036
4037 VideoTrackList& HTMLMediaElement::videoTracks()
4038 {
4039     if (!m_videoTracks)
4040         m_videoTracks = VideoTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
4041
4042     return *m_videoTracks;
4043 }
4044
4045 void HTMLMediaElement::didAddTextTrack(HTMLTrackElement& trackElement)
4046 {
4047     ASSERT(trackElement.hasTagName(trackTag));
4048
4049     // 4.8.10.12.3 Sourcing out-of-band text tracks
4050     // When a track element's parent element changes and the new parent is a media element,
4051     // then the user agent must add the track element's corresponding text track to the
4052     // media element's list of text tracks ... [continues in TextTrackList::append]
4053     addTextTrack(trackElement.track());
4054
4055     // Do not schedule the track loading until parsing finishes so we don't start before all tracks
4056     // in the markup have been added.
4057     if (!m_parsingInProgress)
4058         scheduleDelayedAction(ConfigureTextTracks);
4059
4060     if (hasMediaControls())
4061         mediaControls()->closedCaptionTracksChanged();
4062 }
4063
4064 void HTMLMediaElement::didRemoveTextTrack(HTMLTrackElement& trackElement)
4065 {
4066     ASSERT(trackElement.hasTagName(trackTag));
4067
4068     auto& textTrack = trackElement.track();
4069
4070     textTrack.setHasBeenConfigured(false);
4071
4072     if (!m_textTracks)
4073         return;
4074
4075     // 4.8.10.12.3 Sourcing out-of-band text tracks
4076     // When a track element's parent element changes and the old parent was a media element,
4077     // then the user agent must remove the track element's corresponding text track from the
4078     // media element's list of text tracks.
4079     removeTextTrack(textTrack);
4080
4081     m_textTracksWhenResourceSelectionBegan.removeFirst(&textTrack);
4082 }
4083
4084 void HTMLMediaElement::configureTextTrackGroup(const TrackGroup& group)
4085 {
4086     ASSERT(group.tracks.size());
4087
4088     Page* page = document().page();
4089     CaptionUserPreferences* captionPreferences = page ? &page->group().captionPreferences() : 0;
4090     CaptionUserPreferences::CaptionDisplayMode displayMode = captionPreferences ? captionPreferences->captionDisplayMode() : CaptionUserPreferences::Automatic;
4091
4092     // First, find the track in the group that should be enabled (if any).
4093     Vector<RefPtr<TextTrack>> currentlyEnabledTracks;
4094     RefPtr<TextTrack> trackToEnable;
4095     RefPtr<TextTrack> defaultTrack;
4096     RefPtr<TextTrack> fallbackTrack;
4097     RefPtr<TextTrack> forcedSubitleTrack;
4098     int highestTrackScore = 0;
4099     int highestForcedScore = 0;
4100