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