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