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