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