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