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