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