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