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