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