0e410fd54c53c13439d30a4f266b87251a53e7a2
[WebKit-https.git] / Source / WebCore / html / HTMLMediaElement.cpp
1 /*
2  * Copyright (C) 2007-2015 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 #if ENABLE(VIDEO)
28 #include "HTMLMediaElement.h"
29
30 #include "ApplicationCacheHost.h"
31 #include "ApplicationCacheResource.h"
32 #include "Attribute.h"
33 #include "CSSPropertyNames.h"
34 #include "CSSValueKeywords.h"
35 #include "ChromeClient.h"
36 #include "ClientRect.h"
37 #include "ClientRectList.h"
38 #include "ContentSecurityPolicy.h"
39 #include "ContentType.h"
40 #include "CookieJar.h"
41 #include "DiagnosticLoggingClient.h"
42 #include "DiagnosticLoggingKeys.h"
43 #include "DisplaySleepDisabler.h"
44 #include "Document.h"
45 #include "DocumentLoader.h"
46 #include "ElementIterator.h"
47 #include "EventNames.h"
48 #include "ExceptionCodePlaceholder.h"
49 #include "FrameLoader.h"
50 #include "FrameLoaderClient.h"
51 #include "FrameView.h"
52 #include "HTMLSourceElement.h"
53 #include "HTMLVideoElement.h"
54 #include "JSDOMError.h"
55 #include "JSHTMLMediaElement.h"
56 #include "Language.h"
57 #include "Logging.h"
58 #include "MIMETypeRegistry.h"
59 #include "MainFrame.h"
60 #include "MediaController.h"
61 #include "MediaControls.h"
62 #include "MediaDocument.h"
63 #include "MediaError.h"
64 #include "MediaFragmentURIParser.h"
65 #include "MediaKeyEvent.h"
66 #include "MediaList.h"
67 #include "MediaPlayer.h"
68 #include "MediaQueryEvaluator.h"
69 #include "MediaResourceLoader.h"
70 #include "MemoryPressureHandler.h"
71 #include "NetworkingContext.h"
72 #include "NoEventDispatchAssertion.h"
73 #include "PageGroup.h"
74 #include "PageThrottler.h"
75 #include "PlatformMediaSessionManager.h"
76 #include "ProgressTracker.h"
77 #include "RenderLayerCompositor.h"
78 #include "RenderVideo.h"
79 #include "RenderView.h"
80 #include "ResourceLoadInfo.h"
81 #include "ScriptController.h"
82 #include "ScriptSourceCode.h"
83 #include "SecurityPolicy.h"
84 #include "SessionID.h"
85 #include "Settings.h"
86 #include "ShadowRoot.h"
87 #include "TimeRanges.h"
88 #include "UserContentController.h"
89 #include "UserGestureIndicator.h"
90 #include <limits>
91 #include <runtime/Uint8Array.h>
92 #include <wtf/CurrentTime.h>
93 #include <wtf/MathExtras.h>
94 #include <wtf/Ref.h>
95 #include <wtf/text/CString.h>
96
97 #if ENABLE(VIDEO_TRACK)
98 #include "AudioTrackList.h"
99 #include "HTMLTrackElement.h"
100 #include "InbandGenericTextTrack.h"
101 #include "InbandTextTrackPrivate.h"
102 #include "InbandWebVTTTextTrack.h"
103 #include "RuntimeEnabledFeatures.h"
104 #include "TextTrackCueList.h"
105 #include "TextTrackList.h"
106 #include "VideoTrackList.h"
107 #endif
108
109 #if ENABLE(WEB_AUDIO)
110 #include "AudioSourceProvider.h"
111 #include "MediaElementAudioSourceNode.h"
112 #endif
113
114 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
115 #include "WebVideoFullscreenInterface.h"
116 #endif
117
118 #if PLATFORM(IOS)
119 #include "RuntimeApplicationChecks.h"
120 #include "WebVideoFullscreenInterfaceAVKit.h"
121 #endif
122
123 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
124 #include "WebKitPlaybackTargetAvailabilityEvent.h"
125 #endif
126
127 #if ENABLE(MEDIA_SESSION)
128 #include "MediaSession.h"
129 #endif
130
131 #if ENABLE(MEDIA_SOURCE)
132 #include "DOMWindow.h"
133 #include "MediaSource.h"
134 #include "Performance.h"
135 #include "VideoPlaybackQuality.h"
136 #endif
137
138 #if ENABLE(MEDIA_STREAM)
139 #include "DOMURL.h"
140 #include "MediaStream.h"
141 #include "MediaStreamRegistry.h"
142 #endif
143
144 #if ENABLE(ENCRYPTED_MEDIA_V2)
145 #include "MediaKeyNeededEvent.h"
146 #include "MediaKeys.h"
147 #endif
148
149 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
150 #include "JSMediaControlsHost.h"
151 #include "MediaControlsHost.h"
152 #include <bindings/ScriptObject.h>
153 #endif
154
155 namespace WebCore {
156
157 static const double SeekRepeatDelay = 0.1;
158 static const double SeekTime = 0.2;
159 static const double ScanRepeatDelay = 1.5;
160 static const double ScanMaximumRate = 8;
161
162 static void setFlags(unsigned& value, unsigned flags)
163 {
164     value |= flags;
165 }
166
167 static void clearFlags(unsigned& value, unsigned flags)
168 {
169     value &= ~flags;
170 }
171     
172 #if !LOG_DISABLED
173 static String urlForLoggingMedia(const URL& url)
174 {
175     static const unsigned maximumURLLengthForLogging = 128;
176
177     if (url.string().length() < maximumURLLengthForLogging)
178         return url.string();
179     return url.string().substring(0, maximumURLLengthForLogging) + "...";
180 }
181
182 static const char* boolString(bool val)
183 {
184     return val ? "true" : "false";
185 }
186
187 static String actionName(HTMLMediaElementEnums::DelayedActionType action)
188 {
189     StringBuilder actionBuilder;
190
191 #define ACTION(_actionType) \
192     if (action & (HTMLMediaElementEnums::_actionType)) { \
193         if (!actionBuilder.isEmpty()) \
194         actionBuilder.append(", "); \
195         actionBuilder.append(#_actionType); \
196     } \
197
198     ACTION(LoadMediaResource);
199     ACTION(ConfigureTextTracks);
200     ACTION(TextTrackChangesNotification);
201     ACTION(ConfigureTextTrackDisplay);
202     ACTION(CheckPlaybackTargetCompatablity);
203     ACTION(CheckMediaState);
204     ACTION(MediaEngineUpdated);
205
206     return actionBuilder.toString();
207
208 #undef ACTION
209 }
210
211 #endif
212
213 #ifndef LOG_MEDIA_EVENTS
214 // Default to not logging events because so many are generated they can overwhelm the rest of 
215 // the logging.
216 #define LOG_MEDIA_EVENTS 0
217 #endif
218
219 #ifndef LOG_CACHED_TIME_WARNINGS
220 // Default to not logging warnings about excessive drift in the cached media time because it adds a
221 // fair amount of overhead and logging.
222 #define LOG_CACHED_TIME_WARNINGS 0
223 #endif
224
225 #if ENABLE(MEDIA_SOURCE)
226 // URL protocol used to signal that the media source API is being used.
227 static const char* mediaSourceBlobProtocol = "blob";
228 #endif
229
230 #if ENABLE(MEDIA_STREAM)
231 // URL protocol used to signal that the media stream API is being used.
232 static const char* mediaStreamBlobProtocol = "blob";
233 #endif
234
235 using namespace HTMLNames;
236
237 typedef HashMap<Document*, HashSet<HTMLMediaElement*>> DocumentElementSetMap;
238 static DocumentElementSetMap& documentToElementSetMap()
239 {
240     static NeverDestroyed<DocumentElementSetMap> map;
241     return map;
242 }
243
244 static void addElementToDocumentMap(HTMLMediaElement& element, Document& document)
245 {
246     DocumentElementSetMap& map = documentToElementSetMap();
247     HashSet<HTMLMediaElement*> set = map.take(&document);
248     set.add(&element);
249     map.add(&document, set);
250 }
251
252 static void removeElementFromDocumentMap(HTMLMediaElement& element, Document& document)
253 {
254     DocumentElementSetMap& map = documentToElementSetMap();
255     HashSet<HTMLMediaElement*> set = map.take(&document);
256     set.remove(&element);
257     if (!set.isEmpty())
258         map.add(&document, set);
259 }
260
261 #if ENABLE(ENCRYPTED_MEDIA)
262 static ExceptionCode exceptionCodeForMediaKeyException(MediaPlayer::MediaKeyException exception)
263 {
264     switch (exception) {
265     case MediaPlayer::NoError:
266         return 0;
267     case MediaPlayer::InvalidPlayerState:
268         return INVALID_STATE_ERR;
269     case MediaPlayer::KeySystemNotSupported:
270         return NOT_SUPPORTED_ERR;
271     }
272
273     ASSERT_NOT_REACHED();
274     return INVALID_STATE_ERR;
275 }
276 #endif
277
278 #if ENABLE(VIDEO_TRACK)
279 class TrackDisplayUpdateScope {
280 public:
281     TrackDisplayUpdateScope(HTMLMediaElement* mediaElement)
282     {
283         m_mediaElement = mediaElement;
284         m_mediaElement->beginIgnoringTrackDisplayUpdateRequests();
285     }
286     ~TrackDisplayUpdateScope()
287     {
288         ASSERT(m_mediaElement);
289         m_mediaElement->endIgnoringTrackDisplayUpdateRequests();
290     }
291     
292 private:
293     HTMLMediaElement* m_mediaElement;
294 };
295 #endif
296
297 struct HTMLMediaElement::TrackGroup {
298     enum GroupKind { CaptionsAndSubtitles, Description, Chapter, Metadata, Other };
299
300     TrackGroup(GroupKind kind)
301         : visibleTrack(0)
302         , defaultTrack(0)
303         , kind(kind)
304         , hasSrcLang(false)
305     {
306     }
307
308     Vector<RefPtr<TextTrack>> tracks;
309     RefPtr<TextTrack> visibleTrack;
310     RefPtr<TextTrack> defaultTrack;
311     GroupKind kind;
312     bool hasSrcLang;
313 };
314
315 HashSet<HTMLMediaElement*>& HTMLMediaElement::allMediaElements()
316 {
317     static NeverDestroyed<HashSet<HTMLMediaElement*>> elements;
318     return elements;
319 }
320
321 #if ENABLE(MEDIA_SESSION)
322 typedef HashMap<uint64_t, HTMLMediaElement*> IDToElementMap;
323
324 static IDToElementMap& elementIDsToElements()
325 {
326     static NeverDestroyed<IDToElementMap> map;
327     return map;
328 }
329
330 HTMLMediaElement* HTMLMediaElement::elementWithID(uint64_t id)
331 {
332     if (id == HTMLMediaElementInvalidID)
333         return nullptr;
334     
335     return elementIDsToElements().get(id);
336 }
337
338 static uint64_t nextElementID()
339 {
340     static uint64_t elementID = 0;
341     return ++elementID;
342 }
343 #endif
344
345 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& document, bool createdByParser)
346     : HTMLElement(tagName, document)
347     , ActiveDOMObject(&document)
348     , m_pendingActionTimer(*this, &HTMLMediaElement::pendingActionTimerFired)
349     , m_progressEventTimer(*this, &HTMLMediaElement::progressEventTimerFired)
350     , m_playbackProgressTimer(*this, &HTMLMediaElement::playbackProgressTimerFired)
351     , m_scanTimer(*this, &HTMLMediaElement::scanTimerFired)
352     , m_playedTimeRanges()
353     , m_asyncEventQueue(*this)
354     , m_requestedPlaybackRate(1)
355     , m_reportedPlaybackRate(1)
356     , m_defaultPlaybackRate(1)
357     , m_webkitPreservesPitch(true)
358     , m_networkState(NETWORK_EMPTY)
359     , m_readyState(HAVE_NOTHING)
360     , m_readyStateMaximum(HAVE_NOTHING)
361     , m_volume(1.0f)
362     , m_volumeInitialized(false)
363     , m_previousProgressTime(std::numeric_limits<double>::max())
364     , m_clockTimeAtLastUpdateEvent(0)
365     , m_lastTimeUpdateEventMovieTime(MediaTime::positiveInfiniteTime())
366     , m_loadState(WaitingForSource)
367     , m_videoFullscreenMode(VideoFullscreenModeNone)
368 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
369     , m_videoFullscreenGravity(MediaPlayer::VideoGravityResizeAspect)
370 #endif
371     , m_preload(MediaPlayer::Auto)
372     , m_displayMode(Unknown)
373     , m_processingMediaPlayerCallback(0)
374 #if ENABLE(MEDIA_SOURCE)
375     , m_droppedVideoFrames(0)
376 #endif
377     , m_clockTimeAtLastCachedTimeUpdate(0)
378     , m_minimumClockTimeToUpdateCachedTime(0)
379     , m_pendingActionFlags(0)
380     , m_actionAfterScan(Nothing)
381     , m_scanType(Scan)
382     , m_scanDirection(Forward)
383     , m_firstTimePlaying(true)
384     , m_playing(false)
385     , m_isWaitingUntilMediaCanStart(false)
386     , m_shouldDelayLoadEvent(false)
387     , m_haveFiredLoadedData(false)
388     , m_inActiveDocument(true)
389     , m_autoplaying(true)
390     , m_muted(false)
391     , m_explicitlyMuted(false)
392     , m_initiallyMuted(false)
393     , m_paused(true)
394     , m_seeking(false)
395     , m_sentStalledEvent(false)
396     , m_sentEndEvent(false)
397     , m_pausedInternal(false)
398     , m_sendProgressEvents(true)
399     , m_closedCaptionsVisible(false)
400     , m_webkitLegacyClosedCaptionOverride(false)
401     , m_completelyLoaded(false)
402     , m_havePreparedToPlay(false)
403     , m_parsingInProgress(createdByParser)
404     , m_elementIsHidden(document.hidden())
405     , m_creatingControls(false)
406 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
407     , m_mediaControlsDependOnPageScaleFactor(false)
408     , m_haveSetUpCaptionContainer(false)
409 #endif
410 #if ENABLE(VIDEO_TRACK)
411     , m_tracksAreReady(true)
412     , m_haveVisibleTextTrack(false)
413     , m_processingPreferenceChange(false)
414     , m_lastTextTrackUpdateTime(MediaTime(-1, 1))
415     , m_captionDisplayMode(CaptionUserPreferences::Automatic)
416     , m_audioTracks(0)
417     , m_textTracks(0)
418     , m_videoTracks(0)
419     , m_ignoreTrackDisplayUpdate(0)
420 #endif
421 #if ENABLE(WEB_AUDIO)
422     , m_audioSourceNode(0)
423 #endif
424     , m_mediaSession(std::make_unique<MediaElementSession>(*this))
425     , m_reportedExtraMemoryCost(0)
426 #if ENABLE(MEDIA_STREAM)
427     , m_mediaStreamSrcObject(nullptr)
428 #endif
429 {
430     allMediaElements().add(this);
431
432     LOG(Media, "HTMLMediaElement::HTMLMediaElement(%p)", this);
433     setHasCustomStyleResolveCallbacks();
434
435     m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForFullscreen);
436     m_mediaSession->addBehaviorRestriction(MediaElementSession::RequirePageConsentToLoadMedia);
437 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
438     m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureToAutoplayToExternalDevice);
439 #endif
440
441     Settings* settings = document.settings();
442 #if PLATFORM(IOS)
443     m_sendProgressEvents = false;
444 #endif
445
446     if (settings && settings->invisibleAutoplayNotPermitted())
447         m_mediaSession->addBehaviorRestriction(MediaElementSession::InvisibleAutoplayNotPermitted);
448
449     if (document.ownerElement() || !document.isMediaDocument()) {
450         if (settings && settings->videoPlaybackRequiresUserGesture()) {
451             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForVideoRateChange);
452             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForLoad);
453         }
454
455         if (settings && settings->audioPlaybackRequiresUserGesture())
456             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForAudioRateChange);
457
458 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
459         if (settings && (settings->videoPlaybackRequiresUserGesture() || settings->audioPlaybackRequiresUserGesture()))
460             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureToShowPlaybackTargetPicker);
461 #endif
462
463         if (!settings || !settings->mediaDataLoadsAutomatically())
464             m_mediaSession->addBehaviorRestriction(MediaElementSession::AutoPreloadingNotPermitted);
465
466         if (settings && settings->mainContentUserGestureOverrideEnabled())
467             m_mediaSession->addBehaviorRestriction(MediaElementSession::OverrideUserGestureRequirementForMainContent);
468     }
469
470 #if PLATFORM(IOS)
471     if (settings && !settings->videoPlaybackRequiresUserGesture() && !settings->audioPlaybackRequiresUserGesture()) {
472         // Relax RequireUserGestureForFullscreen when videoPlaybackRequiresUserGesture and audioPlaybackRequiresUserGesture is not set:
473         m_mediaSession->removeBehaviorRestriction(MediaElementSession::RequireUserGestureForFullscreen);
474     }
475 #endif
476
477 #if ENABLE(VIDEO_TRACK)
478     if (document.page())
479         m_captionDisplayMode = document.page()->group().captionPreferences().captionDisplayMode();
480 #endif
481
482 #if ENABLE(MEDIA_SESSION)
483     m_elementID = nextElementID();
484     elementIDsToElements().add(m_elementID, this);
485
486     setSessionInternal(document.defaultMediaSession());
487 #endif
488
489     registerWithDocument(document);
490 }
491
492 HTMLMediaElement::~HTMLMediaElement()
493 {
494     LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this);
495
496     allMediaElements().remove(this);
497
498     m_asyncEventQueue.close();
499
500     setShouldDelayLoadEvent(false);
501     unregisterWithDocument(document());
502
503 #if ENABLE(VIDEO_TRACK)
504     if (m_audioTracks) {
505         m_audioTracks->clearElement();
506         for (unsigned i = 0; i < m_audioTracks->length(); ++i)
507             m_audioTracks->item(i)->clearClient();
508     }
509     if (m_textTracks)
510         m_textTracks->clearElement();
511     if (m_textTracks) {
512         for (unsigned i = 0; i < m_textTracks->length(); ++i)
513             m_textTracks->item(i)->clearClient();
514     }
515     if (m_videoTracks) {
516         m_videoTracks->clearElement();
517         for (unsigned i = 0; i < m_videoTracks->length(); ++i)
518             m_videoTracks->item(i)->clearClient();
519     }
520 #endif
521
522 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
523     if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent)) {
524         m_hasPlaybackTargetAvailabilityListeners = false;
525         m_mediaSession->setHasPlaybackTargetAvailabilityListeners(*this, false);
526         updateMediaState();
527     }
528 #endif
529
530     if (m_mediaController) {
531         m_mediaController->removeMediaElement(this);
532         m_mediaController = nullptr;
533     }
534
535 #if ENABLE(MEDIA_SOURCE)
536     closeMediaSource();
537 #endif
538
539 #if ENABLE(ENCRYPTED_MEDIA_V2)
540     setMediaKeys(0);
541 #endif
542
543 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
544     if (m_isolatedWorld)
545         m_isolatedWorld->clearWrappers();
546 #endif
547
548 #if ENABLE(MEDIA_SESSION)
549     if (m_session) {
550         m_session->removeMediaElement(*this);
551         m_session = nullptr;
552     }
553
554     elementIDsToElements().remove(m_elementID);
555 #endif
556
557     m_seekTaskQueue.close();
558     m_promiseTaskQueue.close();
559     m_pauseAfterDetachedTaskQueue.close();
560
561     m_completelyLoaded = true;
562
563     m_player = nullptr;
564     updatePlaybackControlsManager();
565 }
566
567 void HTMLMediaElement::registerWithDocument(Document& document)
568 {
569     m_mediaSession->registerWithDocument(document);
570
571     if (m_isWaitingUntilMediaCanStart)
572         document.addMediaCanStartListener(this);
573
574 #if !PLATFORM(IOS)
575     document.registerForMediaVolumeCallbacks(this);
576     document.registerForPrivateBrowsingStateChangedCallbacks(this);
577 #endif
578
579     document.registerForVisibilityStateChangedCallbacks(this);
580
581 #if ENABLE(VIDEO_TRACK)
582     if (m_requireCaptionPreferencesChangedCallbacks)
583         document.registerForCaptionPreferencesChangedCallbacks(this);
584 #endif
585
586 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
587     if (m_mediaControlsDependOnPageScaleFactor)
588         document.registerForPageScaleFactorChangedCallbacks(this);
589 #endif
590
591 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
592     document.registerForDocumentSuspensionCallbacks(this);
593 #endif
594
595     document.registerForAllowsMediaDocumentInlinePlaybackChangedCallbacks(*this);
596
597     document.addAudioProducer(this);
598     addElementToDocumentMap(*this, document);
599 }
600
601 void HTMLMediaElement::unregisterWithDocument(Document& document)
602 {
603     m_mediaSession->unregisterWithDocument(document);
604
605     if (m_isWaitingUntilMediaCanStart)
606         document.removeMediaCanStartListener(this);
607
608 #if !PLATFORM(IOS)
609     document.unregisterForMediaVolumeCallbacks(this);
610     document.unregisterForPrivateBrowsingStateChangedCallbacks(this);
611 #endif
612
613     document.unregisterForVisibilityStateChangedCallbacks(this);
614
615 #if ENABLE(VIDEO_TRACK)
616     if (m_requireCaptionPreferencesChangedCallbacks)
617         document.unregisterForCaptionPreferencesChangedCallbacks(this);
618 #endif
619
620 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
621     if (m_mediaControlsDependOnPageScaleFactor)
622         document.unregisterForPageScaleFactorChangedCallbacks(this);
623 #endif
624
625 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
626     document.unregisterForDocumentSuspensionCallbacks(this);
627 #endif
628
629     document.unregisterForAllowsMediaDocumentInlinePlaybackChangedCallbacks(*this);
630
631     document.removeAudioProducer(this);
632     removeElementFromDocumentMap(*this, document);
633 }
634
635 void HTMLMediaElement::didMoveToNewDocument(Document* oldDocument)
636 {
637     if (m_shouldDelayLoadEvent) {
638         if (oldDocument)
639             oldDocument->decrementLoadEventDelayCount();
640         document().incrementLoadEventDelayCount();
641     }
642
643     if (oldDocument)
644         unregisterWithDocument(*oldDocument);
645
646     registerWithDocument(document());
647
648     HTMLElement::didMoveToNewDocument(oldDocument);
649     updateShouldAutoplay();
650 }
651
652 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
653 void HTMLMediaElement::prepareForDocumentSuspension()
654 {
655     m_mediaSession->unregisterWithDocument(document());
656 }
657
658 void HTMLMediaElement::resumeFromDocumentSuspension()
659 {
660     m_mediaSession->registerWithDocument(document());
661     updateShouldAutoplay();
662 }
663 #endif
664
665 bool HTMLMediaElement::supportsFocus() const
666 {
667     if (document().isMediaDocument())
668         return false;
669
670     // If no controls specified, we should still be able to focus the element if it has tabIndex.
671     return controls() ||  HTMLElement::supportsFocus();
672 }
673
674 bool HTMLMediaElement::isMouseFocusable() const
675 {
676     return false;
677 }
678
679 void HTMLMediaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
680 {
681     if (name == srcAttr) {
682 #if PLATFORM(IOS)
683         // Note, unless the restriction on requiring user action has been removed,
684         // do not begin downloading data on iOS.
685         if (!value.isNull() && m_mediaSession->dataLoadingPermitted(*this))
686 #else
687         // Trigger a reload, as long as the 'src' attribute is present.
688         if (!value.isNull())
689 #endif
690         {
691             clearMediaPlayer(LoadMediaResource);
692             scheduleDelayedAction(LoadMediaResource);
693         }
694     } else if (name == controlsAttr)
695         configureMediaControls();
696     else if (name == loopAttr)
697         updateSleepDisabling();
698     else if (name == preloadAttr) {
699         if (equalLettersIgnoringASCIICase(value, "none"))
700             m_preload = MediaPlayer::None;
701         else if (equalLettersIgnoringASCIICase(value, "metadata"))
702             m_preload = MediaPlayer::MetaData;
703         else {
704             // The spec does not define an "invalid value default" but "auto" is suggested as the
705             // "missing value default", so use it for everything except "none" and "metadata"
706             m_preload = MediaPlayer::Auto;
707         }
708
709         // The attribute must be ignored if the autoplay attribute is present
710         if (!autoplay() && m_player)
711             m_player->setPreload(m_mediaSession->effectivePreloadForElement(*this));
712
713     } else if (name == mediagroupAttr)
714         setMediaGroup(value);
715     else
716         HTMLElement::parseAttribute(name, value);
717 }
718
719 void HTMLMediaElement::finishParsingChildren()
720 {
721     HTMLElement::finishParsingChildren();
722     m_parsingInProgress = false;
723     
724 #if ENABLE(VIDEO_TRACK)
725     if (descendantsOfType<HTMLTrackElement>(*this).first())
726         scheduleDelayedAction(ConfigureTextTracks);
727 #endif
728 }
729
730 bool HTMLMediaElement::rendererIsNeeded(const RenderStyle& style)
731 {
732     return controls() && HTMLElement::rendererIsNeeded(style);
733 }
734
735 RenderPtr<RenderElement> HTMLMediaElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
736 {
737     return createRenderer<RenderMedia>(*this, WTFMove(style));
738 }
739
740 bool HTMLMediaElement::childShouldCreateRenderer(const Node& child) const
741 {
742 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
743     return hasShadowRootParent(child) && HTMLElement::childShouldCreateRenderer(child);
744 #else
745     if (!hasMediaControls())
746         return false;
747     // <media> doesn't allow its content, including shadow subtree, to
748     // be rendered. So this should return false for most of the children.
749     // One exception is a shadow tree built for rendering controls which should be visible.
750     // So we let them go here by comparing its subtree root with one of the controls.
751     return &mediaControls()->treeScope() == &child.treeScope()
752         && hasShadowRootParent(child)
753         && HTMLElement::childShouldCreateRenderer(child);
754 #endif
755 }
756
757 Node::InsertionNotificationRequest HTMLMediaElement::insertedInto(ContainerNode& insertionPoint)
758 {
759     LOG(Media, "HTMLMediaElement::insertedInto(%p)", this);
760
761     HTMLElement::insertedInto(insertionPoint);
762     if (insertionPoint.inDocument()) {
763         m_inActiveDocument = true;
764
765 #if PLATFORM(IOS)
766         if (m_networkState == NETWORK_EMPTY && !fastGetAttribute(srcAttr).isEmpty() && m_mediaSession->dataLoadingPermitted(*this))
767 #else
768         if (m_networkState == NETWORK_EMPTY && !fastGetAttribute(srcAttr).isEmpty())
769 #endif
770             scheduleDelayedAction(LoadMediaResource);
771     }
772
773     if (!m_explicitlyMuted) {
774         m_explicitlyMuted = true;
775         m_muted = fastHasAttribute(mutedAttr);
776     }
777
778     configureMediaControls();
779     return InsertionDone;
780 }
781
782 void HTMLMediaElement::pauseAfterDetachedTask()
783 {
784     // If we were re-inserted into an active document, no need to pause.
785     if (m_inActiveDocument)
786         return;
787
788     if (hasMediaControls())
789         mediaControls()->hide();
790     if (m_networkState > NETWORK_EMPTY)
791         pause();
792     if (m_videoFullscreenMode != VideoFullscreenModeNone)
793         exitFullscreen();
794
795     if (!m_player)
796         return;
797
798     size_t extraMemoryCost = m_player->extraMemoryCost();
799     if (extraMemoryCost > m_reportedExtraMemoryCost) {
800         JSC::VM& vm = JSDOMWindowBase::commonVM();
801         JSC::JSLockHolder lock(vm);
802
803         size_t extraMemoryCostDelta = extraMemoryCost - m_reportedExtraMemoryCost;
804         m_reportedExtraMemoryCost = extraMemoryCost;
805         // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated.
806         // https://bugs.webkit.org/show_bug.cgi?id=142595
807         vm.heap.deprecatedReportExtraMemory(extraMemoryCostDelta);
808     }
809 }
810
811 void HTMLMediaElement::removedFrom(ContainerNode& insertionPoint)
812 {
813     LOG(Media, "HTMLMediaElement::removedFrom(%p)", this);
814
815     m_inActiveDocument = false;
816     if (insertionPoint.inDocument()) {
817         // Pause asynchronously to let the operation that removed us finish, in case we get inserted back into a document.
818         m_pauseAfterDetachedTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::pauseAfterDetachedTask, this));
819     }
820
821     HTMLElement::removedFrom(insertionPoint);
822 }
823
824 void HTMLMediaElement::willAttachRenderers()
825 {
826     ASSERT(!renderer());
827 }
828
829 void HTMLMediaElement::didAttachRenderers()
830 {
831     if (RenderElement* renderer = this->renderer()) {
832         renderer->updateFromElement();
833         if (m_mediaSession->hasBehaviorRestriction(MediaElementSession::InvisibleAutoplayNotPermitted)
834             || m_mediaSession->hasBehaviorRestriction(MediaElementSession::OverrideUserGestureRequirementForMainContent))
835             renderer->registerForVisibleInViewportCallback();
836     }
837     updateShouldAutoplay();
838 }
839
840 void HTMLMediaElement::willDetachRenderers()
841 {
842     if (renderer())
843         renderer()->unregisterForVisibleInViewportCallback();
844 }
845
846 void HTMLMediaElement::didDetachRenderers()
847 {
848     updateShouldAutoplay();
849 }
850
851 void HTMLMediaElement::didRecalcStyle(Style::Change)
852 {
853     if (renderer())
854         renderer()->updateFromElement();
855 }
856
857 void HTMLMediaElement::scheduleDelayedAction(DelayedActionType actionType)
858 {
859     LOG(Media, "HTMLMediaElement::scheduleDelayedAction(%p) - setting %s flag", this, actionName(actionType).utf8().data());
860
861     if ((actionType & LoadMediaResource) && !(m_pendingActionFlags & LoadMediaResource)) {
862         prepareForLoad();
863         setFlags(m_pendingActionFlags, LoadMediaResource);
864     }
865
866 #if ENABLE(VIDEO_TRACK)
867     if (actionType & ConfigureTextTracks)
868         setFlags(m_pendingActionFlags, ConfigureTextTracks);
869 #endif
870
871 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
872     if (actionType & CheckPlaybackTargetCompatablity)
873         setFlags(m_pendingActionFlags, CheckPlaybackTargetCompatablity);
874 #endif
875
876     if (actionType & CheckMediaState)
877         setFlags(m_pendingActionFlags, CheckMediaState);
878
879     if (actionType & MediaEngineUpdated)
880         setFlags(m_pendingActionFlags, MediaEngineUpdated);
881
882     m_pendingActionTimer.startOneShot(0);
883 }
884
885 void HTMLMediaElement::scheduleNextSourceChild()
886 {
887     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
888     LOG(Media, "HTMLMediaElement::scheduleNextSourceChild(%p) - setting %s flag", this, actionName(LoadMediaResource).utf8().data());
889     setFlags(m_pendingActionFlags, LoadMediaResource);
890     m_pendingActionTimer.startOneShot(0);
891 }
892
893 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
894 {
895 #if LOG_MEDIA_EVENTS
896     LOG(Media, "HTMLMediaElement::scheduleEvent(%p) - scheduling '%s'", this, eventName.string().ascii().data());
897 #endif
898     RefPtr<Event> event = Event::create(eventName, false, true);
899     
900     // Don't set the event target, the event queue will set it in GenericEventQueue::timerFired and setting it here
901     // will trigger an ASSERT if this element has been marked for deletion.
902
903     m_asyncEventQueue.enqueueEvent(WTFMove(event));
904 }
905
906 void HTMLMediaElement::scheduleResolvePendingPlayPromises()
907 {
908     m_promiseTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::resolvePendingPlayPromises, this));
909 }
910
911 void HTMLMediaElement::rejectPendingPlayPromises(DOMError& error)
912 {
913     Vector<PlayPromise> pendingPlayPromises = WTFMove(m_pendingPlayPromises);
914
915     for (auto& promise : pendingPlayPromises)
916         promise.reject(error);
917 }
918
919 void HTMLMediaElement::resolvePendingPlayPromises()
920 {
921     Vector<PlayPromise> pendingPlayPromises = WTFMove(m_pendingPlayPromises);
922
923     for (auto& promise : pendingPlayPromises)
924         promise.resolve(nullptr);
925 }
926
927 void HTMLMediaElement::scheduleNotifyAboutPlaying()
928 {
929     m_promiseTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::notifyAboutPlaying, this));
930 }
931
932 void HTMLMediaElement::notifyAboutPlaying()
933 {
934     dispatchEvent(Event::create(eventNames().playingEvent, false, true));
935     resolvePendingPlayPromises();
936 }
937
938 void HTMLMediaElement::pendingActionTimerFired()
939 {
940     Ref<HTMLMediaElement> protectedThis(*this); // loadNextSourceChild may fire 'beforeload', which can make arbitrary DOM mutations.
941     PendingActionFlags pendingActions = m_pendingActionFlags;
942     m_pendingActionFlags = 0;
943
944 #if ENABLE(VIDEO_TRACK)
945     if (pendingActions & ConfigureTextTracks)
946         configureTextTracks();
947 #endif
948
949     if (pendingActions & LoadMediaResource) {
950         if (m_loadState == LoadingFromSourceElement)
951             loadNextSourceChild();
952         else
953             loadInternal();
954     }
955
956 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
957     if (pendingActions & CheckPlaybackTargetCompatablity && m_isPlayingToWirelessTarget && !m_player->canPlayToWirelessPlaybackTarget()) {
958         LOG(Media, "HTMLMediaElement::pendingActionTimerFired(%p) - calling setShouldPlayToPlaybackTarget(false)", this);
959         m_failedToPlayToWirelessTarget = true;
960         m_player->setShouldPlayToPlaybackTarget(false);
961     }
962
963     if (pendingActions & CheckMediaState)
964         updateMediaState();
965 #endif
966
967     if (pendingActions & MediaEngineUpdated)
968         mediaEngineWasUpdated();
969 }
970
971 MediaError* HTMLMediaElement::error() const
972 {
973     return m_error.get();
974 }
975
976 void HTMLMediaElement::setSrc(const String& url)
977 {
978     setAttribute(srcAttr, url);
979 }
980
981 #if ENABLE(MEDIA_STREAM)
982 void HTMLMediaElement::setSrcObject(ScriptExecutionContext& context, MediaStream* mediaStream)
983 {
984     // FIXME: Setting the srcObject attribute may cause other changes to the media element's internal state:
985     // Specifically, if srcObject is specified, the UA must use it as the source of media, even if the src
986     // attribute is also set or children are present. If the value of srcObject is replaced or set to null
987     // the UA must re-run the media element load algorithm.
988     //
989     // https://bugs.webkit.org/show_bug.cgi?id=124896
990
991     m_mediaStreamSrcObject = mediaStream;
992     setSrc(DOMURL::createPublicURL(context, mediaStream));
993 }
994 #endif
995
996 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
997 {
998     return m_networkState;
999 }
1000
1001 String HTMLMediaElement::canPlayType(const String& mimeType, const String& keySystem, const URL& url) const
1002 {
1003     MediaEngineSupportParameters parameters;
1004     ContentType contentType(mimeType);
1005     parameters.type = contentType.type().convertToASCIILowercase();
1006     parameters.codecs = contentType.parameter(ASCIILiteral("codecs"));
1007     parameters.url = url;
1008 #if ENABLE(ENCRYPTED_MEDIA)
1009     parameters.keySystem = keySystem;
1010 #else
1011     UNUSED_PARAM(keySystem);
1012 #endif
1013     MediaPlayer::SupportsType support = MediaPlayer::supportsType(parameters, this);
1014     String canPlay;
1015
1016     // 4.8.10.3
1017     switch (support)
1018     {
1019         case MediaPlayer::IsNotSupported:
1020             canPlay = emptyString();
1021             break;
1022         case MediaPlayer::MayBeSupported:
1023             canPlay = ASCIILiteral("maybe");
1024             break;
1025         case MediaPlayer::IsSupported:
1026             canPlay = ASCIILiteral("probably");
1027             break;
1028     }
1029     
1030     LOG(Media, "HTMLMediaElement::canPlayType(%p) - [%s, %s, %s] -> %s", this, mimeType.utf8().data(), keySystem.utf8().data(), url.stringCenterEllipsizedToLength().utf8().data(), canPlay.utf8().data());
1031
1032     return canPlay;
1033 }
1034
1035 double HTMLMediaElement::getStartDate() const
1036 {
1037     return m_player->getStartDate().toDouble();
1038 }
1039
1040 void HTMLMediaElement::load()
1041 {
1042     Ref<HTMLMediaElement> protectedThis(*this); // loadInternal may result in a 'beforeload' event, which can make arbitrary DOM mutations.
1043     
1044     LOG(Media, "HTMLMediaElement::load(%p)", this);
1045     
1046     if (!m_mediaSession->dataLoadingPermitted(*this))
1047         return;
1048     if (ScriptController::processingUserGestureForMedia())
1049         removeBehaviorsRestrictionsAfterFirstUserGesture();
1050
1051     prepareForLoad();
1052     loadInternal();
1053     prepareToPlay();
1054 }
1055
1056 void HTMLMediaElement::prepareForLoad()
1057 {
1058     LOG(Media, "HTMLMediaElement::prepareForLoad(%p)", this);
1059
1060     // Perform the cleanup required for the resource load algorithm to run.
1061     stopPeriodicTimers();
1062     m_pendingActionTimer.stop();
1063     // FIXME: Figure out appropriate place to reset LoadTextTrackResource if necessary and set m_pendingActionFlags to 0 here.
1064     m_pendingActionFlags &= ~LoadMediaResource;
1065     m_sentEndEvent = false;
1066     m_sentStalledEvent = false;
1067     m_haveFiredLoadedData = false;
1068     m_completelyLoaded = false;
1069     m_havePreparedToPlay = false;
1070     m_displayMode = Unknown;
1071     m_currentSrc = URL();
1072
1073 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1074     m_failedToPlayToWirelessTarget = false;
1075 #endif
1076
1077     // 1 - Abort any already-running instance of the resource selection algorithm for this element.
1078     m_loadState = WaitingForSource;
1079     m_currentSourceNode = nullptr;
1080
1081     // 2 - If there are any tasks from the media element's media element event task source in 
1082     // one of the task queues, then remove those tasks.
1083     cancelPendingEventsAndCallbacks();
1084
1085     // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
1086     // a task to fire a simple event named abort at the media element.
1087     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
1088         scheduleEvent(eventNames().abortEvent);
1089
1090 #if ENABLE(MEDIA_SOURCE)
1091     closeMediaSource();
1092 #endif
1093
1094     createMediaPlayer();
1095
1096     // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
1097     if (m_networkState != NETWORK_EMPTY) {
1098         // 4.1 - Queue a task to fire a simple event named emptied at the media element.
1099         scheduleEvent(eventNames().emptiedEvent);
1100
1101         // 4.2 - If a fetching process is in progress for the media element, the user agent should stop it.
1102         m_networkState = NETWORK_EMPTY;
1103
1104         // 4.3 - Forget the media element's media-resource-specific tracks.
1105         forgetResourceSpecificTracks();
1106
1107         // 4.4 - If readyState is not set to HAVE_NOTHING, then set it to that state.
1108         m_readyState = HAVE_NOTHING;
1109         m_readyStateMaximum = HAVE_NOTHING;
1110
1111         // 4.5 - If the paused attribute is false, then set it to true.
1112         m_paused = true;
1113
1114         // 4.6 - If seeking is true, set it to false.
1115         clearSeeking();
1116
1117         // 4.7 - Set the current playback position to 0.
1118         //       Set the official playback position to 0.
1119         //       If this changed the official playback position, then queue a task to fire a simple event named timeupdate at the media element.
1120         // FIXME: Add support for firing this event. e.g., scheduleEvent(eventNames().timeUpdateEvent);
1121
1122         // 4.8 - Set the initial playback position to 0.
1123         // FIXME: Make this less subtle. The position only becomes 0 because of the createMediaPlayer() call
1124         // above.
1125         refreshCachedTime();
1126
1127         invalidateCachedTime();
1128
1129         // 4.9 - Set the timeline offset to Not-a-Number (NaN).
1130         // 4.10 - Update the duration attribute to Not-a-Number (NaN).
1131
1132         updateMediaController();
1133 #if ENABLE(VIDEO_TRACK)
1134         updateActiveTextTrackCues(MediaTime::zeroTime());
1135 #endif
1136     }
1137
1138     // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
1139     setPlaybackRate(defaultPlaybackRate());
1140
1141     // 6 - Set the error attribute to null and the autoplaying flag to true.
1142     m_error = nullptr;
1143     m_autoplaying = true;
1144     mediaSession().clientWillBeginAutoplaying();
1145
1146     // 7 - Invoke the media element's resource selection algorithm.
1147
1148     // 8 - Note: Playback of any previously playing media resource for this element stops.
1149
1150     // The resource selection algorithm
1151     // 1 - Set the networkState to NETWORK_NO_SOURCE
1152     m_networkState = NETWORK_NO_SOURCE;
1153
1154     // 2 - Asynchronously await a stable state.
1155
1156     m_playedTimeRanges = TimeRanges::create();
1157
1158     // FIXME: Investigate whether these can be moved into m_networkState != NETWORK_EMPTY block above
1159     // so they are closer to the relevant spec steps.
1160     m_lastSeekTime = MediaTime::zeroTime();
1161
1162     // The spec doesn't say to block the load event until we actually run the asynchronous section
1163     // algorithm, but do it now because we won't start that until after the timer fires and the 
1164     // event may have already fired by then.
1165     MediaPlayer::Preload effectivePreload = m_mediaSession->effectivePreloadForElement(*this);
1166     if (effectivePreload != MediaPlayer::None)
1167         setShouldDelayLoadEvent(true);
1168
1169 #if PLATFORM(IOS)
1170     if (effectivePreload != MediaPlayer::None && m_mediaSession->allowsAutomaticMediaDataLoading(*this))
1171         prepareToPlay();
1172 #endif
1173
1174     configureMediaControls();
1175 }
1176
1177 void HTMLMediaElement::loadInternal()
1178 {
1179     LOG(Media, "HTMLMediaElement::loadInternal(%p)", this);
1180
1181     // Some of the code paths below this function dispatch the BeforeLoad event. This ASSERT helps
1182     // us catch those bugs more quickly without needing all the branches to align to actually
1183     // trigger the event.
1184     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
1185
1186     // If we can't start a load right away, start it later.
1187     if (!m_mediaSession->pageAllowsDataLoading(*this)) {
1188         LOG(Media, "HTMLMediaElement::loadInternal(%p) - not allowed to load in background, waiting", this);
1189         setShouldDelayLoadEvent(false);
1190         if (m_isWaitingUntilMediaCanStart)
1191             return;
1192         m_isWaitingUntilMediaCanStart = true;
1193         document().addMediaCanStartListener(this);
1194         return;
1195     }
1196
1197     clearFlags(m_pendingActionFlags, LoadMediaResource);
1198
1199     // Once the page has allowed an element to load media, it is free to load at will. This allows a 
1200     // playlist that starts in a foreground tab to continue automatically if the tab is subsequently 
1201     // put into the background.
1202     m_mediaSession->removeBehaviorRestriction(MediaElementSession::RequirePageConsentToLoadMedia);
1203
1204 #if ENABLE(VIDEO_TRACK)
1205     if (hasMediaControls())
1206         mediaControls()->changedClosedCaptionsVisibility();
1207
1208     // HTMLMediaElement::textTracksAreReady will need "... the text tracks whose mode was not in the
1209     // disabled state when the element's resource selection algorithm last started".
1210     m_textTracksWhenResourceSelectionBegan.clear();
1211     if (m_textTracks) {
1212         for (unsigned i = 0; i < m_textTracks->length(); ++i) {
1213             TextTrack* track = m_textTracks->item(i);
1214             if (track->mode() != TextTrack::Mode::Disabled)
1215                 m_textTracksWhenResourceSelectionBegan.append(track);
1216         }
1217     }
1218 #endif
1219
1220     selectMediaResource();
1221 }
1222
1223 void HTMLMediaElement::selectMediaResource()
1224 {
1225     LOG(Media, "HTMLMediaElement::selectMediaResource(%p)", this);
1226
1227     ASSERT(m_player);
1228     if (!m_player)
1229         return;
1230
1231     enum Mode { attribute, children };
1232
1233     // 3 - If the media element has a src attribute, then let mode be attribute.
1234     Mode mode = attribute;
1235     if (!fastHasAttribute(srcAttr)) {
1236         // Otherwise, if the media element does not have a src attribute but has a source 
1237         // element child, then let mode be children and let candidate be the first such 
1238         // source element child in tree order.
1239         if (auto firstSource = childrenOfType<HTMLSourceElement>(*this).first()) {
1240             mode = children;
1241             m_nextChildNodeToConsider = firstSource;
1242             m_currentSourceNode = nullptr;
1243         } else {
1244             // Otherwise the media element has neither a src attribute nor a source element 
1245             // child: set the networkState to NETWORK_EMPTY, and abort these steps; the 
1246             // synchronous section ends.
1247             m_loadState = WaitingForSource;
1248             setShouldDelayLoadEvent(false);
1249             m_networkState = NETWORK_EMPTY;
1250
1251             LOG(Media, "HTMLMediaElement::selectMediaResource(%p) - nothing to load", this);
1252             return;
1253         }
1254     }
1255
1256     // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event), 
1257     // and set its networkState to NETWORK_LOADING.
1258     setShouldDelayLoadEvent(true);
1259     m_networkState = NETWORK_LOADING;
1260
1261     // 5 - Queue a task to fire a simple event named loadstart at the media element.
1262     scheduleEvent(eventNames().loadstartEvent);
1263
1264     // 6 - If mode is attribute, then run these substeps
1265     if (mode == attribute) {
1266         m_loadState = LoadingFromSrcAttr;
1267
1268         // If the src attribute's value is the empty string ... jump down to the failed step below
1269         URL mediaURL = getNonEmptyURLAttribute(srcAttr);
1270         if (mediaURL.isEmpty()) {
1271             mediaLoadingFailed(MediaPlayer::FormatError);
1272             LOG(Media, "HTMLMediaElement::selectMediaResource(%p) -  empty 'src'", this);
1273             return;
1274         }
1275
1276         if (!isSafeToLoadURL(mediaURL, Complain) || !dispatchBeforeLoadEvent(mediaURL.string())) {
1277             mediaLoadingFailed(MediaPlayer::FormatError);
1278             return;
1279         }
1280
1281         // No type or key system information is available when the url comes
1282         // from the 'src' attribute so MediaPlayer
1283         // will have to pick a media engine based on the file extension.
1284         ContentType contentType((String()));
1285         loadResource(mediaURL, contentType, String());
1286         LOG(Media, "HTMLMediaElement::selectMediaResource(%p) - using 'src' attribute url", this);
1287         return;
1288     }
1289
1290     // Otherwise, the source elements will be used
1291     loadNextSourceChild();
1292 }
1293
1294 void HTMLMediaElement::loadNextSourceChild()
1295 {
1296     ContentType contentType((String()));
1297     String keySystem;
1298     URL mediaURL = selectNextSourceChild(&contentType, &keySystem, Complain);
1299     if (!mediaURL.isValid()) {
1300         waitForSourceChange();
1301         return;
1302     }
1303
1304     // Recreate the media player for the new url
1305     createMediaPlayer();
1306
1307     m_loadState = LoadingFromSourceElement;
1308     loadResource(mediaURL, contentType, keySystem);
1309 }
1310
1311 void HTMLMediaElement::loadResource(const URL& initialURL, ContentType& contentType, const String& keySystem)
1312 {
1313     ASSERT(isSafeToLoadURL(initialURL, Complain));
1314
1315     LOG(Media, "HTMLMediaElement::loadResource(%p) - %s, %s, %s", this, urlForLoggingMedia(initialURL).utf8().data(), contentType.raw().utf8().data(), keySystem.utf8().data());
1316
1317     Frame* frame = document().frame();
1318     if (!frame) {
1319         mediaLoadingFailed(MediaPlayer::FormatError);
1320         return;
1321     }
1322
1323     Page* page = frame->page();
1324     if (!page) {
1325         mediaLoadingFailed(MediaPlayer::FormatError);
1326         return;
1327     }
1328
1329     URL url = initialURL;
1330     if (!frame->loader().willLoadMediaElementURL(url)) {
1331         mediaLoadingFailed(MediaPlayer::FormatError);
1332         return;
1333     }
1334
1335 #if ENABLE(CONTENT_EXTENSIONS)
1336     ResourceRequest request(url);
1337     DocumentLoader* documentLoader = frame->loader().documentLoader();
1338
1339     if (documentLoader && page->userContentProvider().processContentExtensionRulesForLoad(request, ResourceType::Media, *documentLoader) == ContentExtensions::BlockedStatus::Blocked) {
1340         request = { };
1341         mediaLoadingFailed(MediaPlayer::FormatError);
1342         return;
1343     }
1344 #endif
1345
1346     // The resource fetch algorithm 
1347     m_networkState = NETWORK_LOADING;
1348
1349     // If the url should be loaded from the application cache, pass the url of the cached file
1350     // to the media engine.
1351     ApplicationCacheHost* cacheHost = frame->loader().documentLoader()->applicationCacheHost();
1352     ApplicationCacheResource* resource = 0;
1353     if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(url), resource)) {
1354         // Resources that are not present in the manifest will always fail to load (at least, after the
1355         // cache has been primed the first time), making the testing of offline applications simpler.
1356         if (!resource || resource->path().isEmpty()) {
1357             mediaLoadingFailed(MediaPlayer::NetworkError);
1358             return;
1359         }
1360     }
1361
1362     // Log that we started loading a media element.
1363     page->diagnosticLoggingClient().logDiagnosticMessageWithValue(DiagnosticLoggingKeys::mediaKey(), isVideo() ? DiagnosticLoggingKeys::videoKey() : DiagnosticLoggingKeys::audioKey(), DiagnosticLoggingKeys::loadingKey(), ShouldSample::No);
1364
1365     m_firstTimePlaying = true;
1366
1367     // Set m_currentSrc *before* changing to the cache url, the fact that we are loading from the app
1368     // cache is an internal detail not exposed through the media element API.
1369     m_currentSrc = url;
1370
1371     if (resource) {
1372         url = ApplicationCacheHost::createFileURL(resource->path());
1373         LOG(Media, "HTMLMediaElement::loadResource(%p) - will load from app cache -> %s", this, urlForLoggingMedia(url).utf8().data());
1374     }
1375
1376     LOG(Media, "HTMLMediaElement::loadResource(%p) - m_currentSrc -> %s", this, urlForLoggingMedia(m_currentSrc).utf8().data());
1377
1378     if (m_sendProgressEvents)
1379         startProgressEventTimer();
1380
1381     bool privateMode = document().page() && document().page()->usesEphemeralSession();
1382     m_player->setPrivateBrowsingMode(privateMode);
1383
1384     // Reset display mode to force a recalculation of what to show because we are resetting the player.
1385     setDisplayMode(Unknown);
1386
1387     if (!autoplay())
1388         m_player->setPreload(m_mediaSession->effectivePreloadForElement(*this));
1389     m_player->setPreservesPitch(m_webkitPreservesPitch);
1390
1391     if (!m_explicitlyMuted) {
1392         m_explicitlyMuted = true;
1393         m_muted = fastHasAttribute(mutedAttr);
1394     }
1395
1396     updateVolume();
1397
1398     bool loadAttempted = false;
1399 #if ENABLE(MEDIA_SOURCE)
1400     ASSERT(!m_mediaSource);
1401
1402     if (url.protocolIs(mediaSourceBlobProtocol))
1403         m_mediaSource = MediaSource::lookup(url.string());
1404
1405     if (m_mediaSource) {
1406         if (m_mediaSource->attachToElement(this))
1407             m_player->load(url, contentType, m_mediaSource.get());
1408         else {
1409             // Forget our reference to the MediaSource, so we leave it alone
1410             // while processing remainder of load failure.
1411             m_mediaSource = nullptr;
1412             mediaLoadingFailed(MediaPlayer::FormatError);
1413         }
1414         loadAttempted = true;
1415     }
1416 #endif
1417
1418 #if ENABLE(MEDIA_STREAM)
1419     if (!loadAttempted) {
1420         if (!m_mediaStreamSrcObject && url.protocolIs(mediaStreamBlobProtocol))
1421             m_mediaStreamSrcObject = MediaStreamRegistry::shared().lookUp(url);
1422
1423         if (m_mediaStreamSrcObject) {
1424             loadAttempted = true;
1425             if (!m_player->load(m_mediaStreamSrcObject->privateStream()))
1426                 mediaLoadingFailed(MediaPlayer::FormatError);
1427         }
1428     }
1429 #endif
1430
1431     if (!loadAttempted && !m_player->load(url, contentType, keySystem))
1432         mediaLoadingFailed(MediaPlayer::FormatError);
1433
1434     // If there is no poster to display, allow the media engine to render video frames as soon as
1435     // they are available.
1436     updateDisplayState();
1437
1438     if (renderer())
1439         renderer()->updateFromElement();
1440 }
1441
1442 #if ENABLE(VIDEO_TRACK)
1443 static bool trackIndexCompare(TextTrack* a,
1444                               TextTrack* b)
1445 {
1446     return a->trackIndex() - b->trackIndex() < 0;
1447 }
1448
1449 static bool eventTimeCueCompare(const std::pair<MediaTime, TextTrackCue*>& a, const std::pair<MediaTime, TextTrackCue*>& b)
1450 {
1451     // 12 - Sort the tasks in events in ascending time order (tasks with earlier
1452     // times first).
1453     if (a.first != b.first)
1454         return a.first - b.first < MediaTime::zeroTime();
1455
1456     // If the cues belong to different text tracks, it doesn't make sense to
1457     // compare the two tracks by the relative cue order, so return the relative
1458     // track order.
1459     if (a.second->track() != b.second->track())
1460         return trackIndexCompare(a.second->track(), b.second->track());
1461
1462     // 12 - Further sort tasks in events that have the same time by the
1463     // relative text track cue order of the text track cues associated
1464     // with these tasks.
1465     return a.second->cueIndex() - b.second->cueIndex() < 0;
1466 }
1467
1468 static bool compareCueInterval(const CueInterval& one, const CueInterval& two)
1469 {
1470     return one.data()->isOrderedBefore(two.data());
1471 };
1472
1473
1474 void HTMLMediaElement::updateActiveTextTrackCues(const MediaTime& movieTime)
1475 {
1476     // 4.8.10.8 Playing the media resource
1477
1478     //  If the current playback position changes while the steps are running,
1479     //  then the user agent must wait for the steps to complete, and then must
1480     //  immediately rerun the steps.
1481     if (ignoreTrackDisplayUpdateRequests())
1482         return;
1483
1484     LOG(Media, "HTMLMediaElement::updateActiveTextTrackCues(%p)", this);
1485
1486     // 1 - Let current cues be a list of cues, initialized to contain all the
1487     // cues of all the hidden, showing, or showing by default text tracks of the
1488     // media element (not the disabled ones) whose start times are less than or
1489     // equal to the current playback position and whose end times are greater
1490     // than the current playback position.
1491     CueList currentCues;
1492
1493     // The user agent must synchronously unset [the text track cue active] flag
1494     // whenever ... the media element's readyState is changed back to HAVE_NOTHING.
1495     if (m_readyState != HAVE_NOTHING && m_player) {
1496         currentCues = m_cueTree.allOverlaps(m_cueTree.createInterval(movieTime, movieTime));
1497         if (currentCues.size() > 1)
1498             std::sort(currentCues.begin(), currentCues.end(), &compareCueInterval);
1499     }
1500
1501     CueList previousCues;
1502     CueList missedCues;
1503
1504     // 2 - Let other cues be a list of cues, initialized to contain all the cues
1505     // of hidden, showing, and showing by default text tracks of the media
1506     // element that are not present in current cues.
1507     previousCues = m_currentlyActiveCues;
1508
1509     // 3 - Let last time be the current playback position at the time this
1510     // algorithm was last run for this media element, if this is not the first
1511     // time it has run.
1512     MediaTime lastTime = m_lastTextTrackUpdateTime;
1513
1514     // 4 - If the current playback position has, since the last time this
1515     // algorithm was run, only changed through its usual monotonic increase
1516     // during normal playback, then let missed cues be the list of cues in other
1517     // cues whose start times are greater than or equal to last time and whose
1518     // end times are less than or equal to the current playback position.
1519     // Otherwise, let missed cues be an empty list.
1520     if (lastTime >= MediaTime::zeroTime() && m_lastSeekTime < movieTime) {
1521         CueList potentiallySkippedCues =
1522             m_cueTree.allOverlaps(m_cueTree.createInterval(lastTime, movieTime));
1523
1524         for (size_t i = 0; i < potentiallySkippedCues.size(); ++i) {
1525             MediaTime cueStartTime = potentiallySkippedCues[i].low();
1526             MediaTime cueEndTime = potentiallySkippedCues[i].high();
1527
1528             // Consider cues that may have been missed since the last seek time.
1529             if (cueStartTime > std::max(m_lastSeekTime, lastTime) && cueEndTime < movieTime)
1530                 missedCues.append(potentiallySkippedCues[i]);
1531         }
1532     }
1533
1534     m_lastTextTrackUpdateTime = movieTime;
1535
1536     // 5 - If the time was reached through the usual monotonic increase of the
1537     // current playback position during normal playback, and if the user agent
1538     // has not fired a timeupdate event at the element in the past 15 to 250ms
1539     // and is not still running event handlers for such an event, then the user
1540     // agent must queue a task to fire a simple event named timeupdate at the
1541     // element. (In the other cases, such as explicit seeks, relevant events get
1542     // fired as part of the overall process of changing the current playback
1543     // position.)
1544     if (!m_paused && m_lastSeekTime <= lastTime)
1545         scheduleTimeupdateEvent(false);
1546
1547     // Explicitly cache vector sizes, as their content is constant from here.
1548     size_t currentCuesSize = currentCues.size();
1549     size_t missedCuesSize = missedCues.size();
1550     size_t previousCuesSize = previousCues.size();
1551
1552     // 6 - If all of the cues in current cues have their text track cue active
1553     // flag set, none of the cues in other cues have their text track cue active
1554     // flag set, and missed cues is empty, then abort these steps.
1555     bool activeSetChanged = missedCuesSize;
1556
1557     for (size_t i = 0; !activeSetChanged && i < previousCuesSize; ++i)
1558         if (!currentCues.contains(previousCues[i]) && previousCues[i].data()->isActive())
1559             activeSetChanged = true;
1560
1561     for (size_t i = 0; i < currentCuesSize; ++i) {
1562         TextTrackCue* cue = currentCues[i].data();
1563
1564         if (cue->isRenderable())
1565             toVTTCue(cue)->updateDisplayTree(movieTime);
1566
1567         if (!cue->isActive())
1568             activeSetChanged = true;
1569     }
1570
1571     if (!activeSetChanged)
1572         return;
1573
1574     // 7 - If the time was reached through the usual monotonic increase of the
1575     // current playback position during normal playback, and there are cues in
1576     // other cues that have their text track cue pause-on-exi flag set and that
1577     // either have their text track cue active flag set or are also in missed
1578     // cues, then immediately pause the media element.
1579     for (size_t i = 0; !m_paused && i < previousCuesSize; ++i) {
1580         if (previousCues[i].data()->pauseOnExit()
1581             && previousCues[i].data()->isActive()
1582             && !currentCues.contains(previousCues[i]))
1583             pause();
1584     }
1585
1586     for (size_t i = 0; !m_paused && i < missedCuesSize; ++i) {
1587         if (missedCues[i].data()->pauseOnExit())
1588             pause();
1589     }
1590
1591     // 8 - Let events be a list of tasks, initially empty. Each task in this
1592     // list will be associated with a text track, a text track cue, and a time,
1593     // which are used to sort the list before the tasks are queued.
1594     Vector<std::pair<MediaTime, TextTrackCue*>> eventTasks;
1595
1596     // 8 - Let affected tracks be a list of text tracks, initially empty.
1597     Vector<TextTrack*> affectedTracks;
1598
1599     for (size_t i = 0; i < missedCuesSize; ++i) {
1600         // 9 - For each text track cue in missed cues, prepare an event named enter
1601         // for the TextTrackCue object with the text track cue start time.
1602         eventTasks.append(std::make_pair(missedCues[i].data()->startMediaTime(),
1603                                          missedCues[i].data()));
1604
1605         // 10 - For each text track [...] in missed cues, prepare an event
1606         // named exit for the TextTrackCue object with the  with the later of
1607         // the text track cue end time and the text track cue start time.
1608
1609         // Note: An explicit task is added only if the cue is NOT a zero or
1610         // negative length cue. Otherwise, the need for an exit event is
1611         // checked when these tasks are actually queued below. This doesn't
1612         // affect sorting events before dispatch either, because the exit
1613         // event has the same time as the enter event.
1614         if (missedCues[i].data()->startMediaTime() < missedCues[i].data()->endMediaTime())
1615             eventTasks.append(std::make_pair(missedCues[i].data()->endMediaTime(), missedCues[i].data()));
1616     }
1617
1618     for (size_t i = 0; i < previousCuesSize; ++i) {
1619         // 10 - For each text track cue in other cues that has its text
1620         // track cue active flag set prepare an event named exit for the
1621         // TextTrackCue object with the text track cue end time.
1622         if (!currentCues.contains(previousCues[i]))
1623             eventTasks.append(std::make_pair(previousCues[i].data()->endMediaTime(),
1624                                              previousCues[i].data()));
1625     }
1626
1627     for (size_t i = 0; i < currentCuesSize; ++i) {
1628         // 11 - For each text track cue in current cues that does not have its
1629         // text track cue active flag set, prepare an event named enter for the
1630         // TextTrackCue object with the text track cue start time.
1631         if (!previousCues.contains(currentCues[i]))
1632             eventTasks.append(std::make_pair(currentCues[i].data()->startMediaTime(),
1633                                              currentCues[i].data()));
1634     }
1635
1636     // 12 - Sort the tasks in events in ascending time order (tasks with earlier
1637     // times first).
1638     std::sort(eventTasks.begin(), eventTasks.end(), eventTimeCueCompare);
1639
1640     for (size_t i = 0; i < eventTasks.size(); ++i) {
1641         if (!affectedTracks.contains(eventTasks[i].second->track()))
1642             affectedTracks.append(eventTasks[i].second->track());
1643
1644         // 13 - Queue each task in events, in list order.
1645         RefPtr<Event> event;
1646
1647         // Each event in eventTasks may be either an enterEvent or an exitEvent,
1648         // depending on the time that is associated with the event. This
1649         // correctly identifies the type of the event, if the startTime is
1650         // less than the endTime in the cue.
1651         if (eventTasks[i].second->startTime() >= eventTasks[i].second->endTime()) {
1652             event = Event::create(eventNames().enterEvent, false, false);
1653             event->setTarget(eventTasks[i].second);
1654             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1655
1656             event = Event::create(eventNames().exitEvent, false, false);
1657             event->setTarget(eventTasks[i].second);
1658             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1659         } else {
1660             if (eventTasks[i].first == eventTasks[i].second->startMediaTime())
1661                 event = Event::create(eventNames().enterEvent, false, false);
1662             else
1663                 event = Event::create(eventNames().exitEvent, false, false);
1664
1665             event->setTarget(eventTasks[i].second);
1666             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1667         }
1668     }
1669
1670     // 14 - Sort affected tracks in the same order as the text tracks appear in
1671     // the media element's list of text tracks, and remove duplicates.
1672     std::sort(affectedTracks.begin(), affectedTracks.end(), trackIndexCompare);
1673
1674     // 15 - For each text track in affected tracks, in the list order, queue a
1675     // task to fire a simple event named cuechange at the TextTrack object, and, ...
1676     for (size_t i = 0; i < affectedTracks.size(); ++i) {
1677         RefPtr<Event> event = Event::create(eventNames().cuechangeEvent, false, false);
1678         event->setTarget(affectedTracks[i]);
1679
1680         m_asyncEventQueue.enqueueEvent(WTFMove(event));
1681
1682         // ... if the text track has a corresponding track element, to then fire a
1683         // simple event named cuechange at the track element as well.
1684         if (is<LoadableTextTrack>(*affectedTracks[i])) {
1685             RefPtr<Event> event = Event::create(eventNames().cuechangeEvent, false, false);
1686             HTMLTrackElement* trackElement = downcast<LoadableTextTrack>(*affectedTracks[i]).trackElement();
1687             ASSERT(trackElement);
1688             event->setTarget(trackElement);
1689             
1690             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1691         }
1692     }
1693
1694     // 16 - Set the text track cue active flag of all the cues in the current
1695     // cues, and unset the text track cue active flag of all the cues in the
1696     // other cues.
1697     for (size_t i = 0; i < currentCuesSize; ++i)
1698         currentCues[i].data()->setIsActive(true);
1699
1700     for (size_t i = 0; i < previousCuesSize; ++i)
1701         if (!currentCues.contains(previousCues[i]))
1702             previousCues[i].data()->setIsActive(false);
1703
1704     // Update the current active cues.
1705     m_currentlyActiveCues = currentCues;
1706
1707     if (activeSetChanged)
1708         updateTextTrackDisplay();
1709 }
1710
1711 bool HTMLMediaElement::textTracksAreReady() const
1712 {
1713     // 4.8.10.12.1 Text track model
1714     // ...
1715     // The text tracks of a media element are ready if all the text tracks whose mode was not 
1716     // in the disabled state when the element's resource selection algorithm last started now
1717     // have a text track readiness state of loaded or failed to load.
1718     for (unsigned i = 0; i < m_textTracksWhenResourceSelectionBegan.size(); ++i) {
1719         if (m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::Loading
1720             || m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::NotLoaded)
1721             return false;
1722     }
1723
1724     return true;
1725 }
1726
1727 void HTMLMediaElement::textTrackReadyStateChanged(TextTrack* track)
1728 {
1729     if (m_player && m_textTracksWhenResourceSelectionBegan.contains(track)) {
1730         if (track->readinessState() != TextTrack::Loading)
1731             setReadyState(m_player->readyState());
1732     } else {
1733         // The track readiness state might have changed as a result of the user
1734         // clicking the captions button. In this case, a check whether all the
1735         // resources have failed loading should be done in order to hide the CC button.
1736         if (hasMediaControls() && track->readinessState() == TextTrack::FailedToLoad)
1737             mediaControls()->refreshClosedCaptionsButtonVisibility();
1738     }
1739 }
1740
1741 void HTMLMediaElement::audioTrackEnabledChanged(AudioTrack* track)
1742 {
1743     ASSERT(track);
1744     if (m_audioTracks && m_audioTracks->contains(*track))
1745         m_audioTracks->scheduleChangeEvent();
1746 }
1747
1748 void HTMLMediaElement::textTrackModeChanged(TextTrack* track)
1749 {
1750     bool trackIsLoaded = true;
1751     if (track->trackType() == TextTrack::TrackElement) {
1752         trackIsLoaded = false;
1753         for (auto& trackElement : childrenOfType<HTMLTrackElement>(*this)) {
1754             if (trackElement.track() == track) {
1755                 if (trackElement.readyState() == HTMLTrackElement::LOADING || trackElement.readyState() == HTMLTrackElement::LOADED)
1756                     trackIsLoaded = true;
1757                 break;
1758             }
1759         }
1760     }
1761
1762     // If this is the first added track, create the list of text tracks.
1763     if (!m_textTracks)
1764         m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
1765     
1766     // Mark this track as "configured" so configureTextTracks won't change the mode again.
1767     track->setHasBeenConfigured(true);
1768     
1769     if (track->mode() != TextTrack::Mode::Disabled && trackIsLoaded)
1770         textTrackAddCues(track, track->cues());
1771
1772     configureTextTrackDisplay(AssumeTextTrackVisibilityChanged);
1773
1774     if (m_textTracks && m_textTracks->contains(*track))
1775         m_textTracks->scheduleChangeEvent();
1776
1777 #if ENABLE(AVF_CAPTIONS)
1778     if (track->trackType() == TextTrack::TrackElement && m_player)
1779         m_player->notifyTrackModeChanged();
1780 #endif
1781 }
1782
1783 void HTMLMediaElement::videoTrackSelectedChanged(VideoTrack* track)
1784 {
1785     ASSERT(track);
1786     if (m_videoTracks && m_videoTracks->contains(*track))
1787         m_videoTracks->scheduleChangeEvent();
1788 }
1789
1790 void HTMLMediaElement::textTrackKindChanged(TextTrack* track)
1791 {
1792     if (track->kind() != TextTrack::Kind::Captions && track->kind() != TextTrack::Kind::Subtitles && track->mode() == TextTrack::Mode::Showing)
1793         track->setMode(TextTrack::Mode::Hidden);
1794 }
1795
1796 void HTMLMediaElement::beginIgnoringTrackDisplayUpdateRequests()
1797 {
1798     ++m_ignoreTrackDisplayUpdate;
1799 }
1800
1801 void HTMLMediaElement::endIgnoringTrackDisplayUpdateRequests()
1802 {
1803     ASSERT(m_ignoreTrackDisplayUpdate);
1804     --m_ignoreTrackDisplayUpdate;
1805     if (!m_ignoreTrackDisplayUpdate && m_inActiveDocument)
1806         updateActiveTextTrackCues(currentMediaTime());
1807 }
1808
1809 void HTMLMediaElement::textTrackAddCues(TextTrack* track, const TextTrackCueList* cues) 
1810 {
1811     if (track->mode() == TextTrack::Mode::Disabled)
1812         return;
1813
1814     TrackDisplayUpdateScope scope(this);
1815     for (size_t i = 0; i < cues->length(); ++i)
1816         textTrackAddCue(track, cues->item(i));
1817 }
1818
1819 void HTMLMediaElement::textTrackRemoveCues(TextTrack*, const TextTrackCueList* cues)
1820 {
1821     TrackDisplayUpdateScope scope(this);
1822     for (size_t i = 0; i < cues->length(); ++i)
1823         textTrackRemoveCue(cues->item(i)->track(), cues->item(i));
1824 }
1825
1826 void HTMLMediaElement::textTrackAddCue(TextTrack* track, PassRefPtr<TextTrackCue> prpCue)
1827 {
1828     if (track->mode() == TextTrack::Mode::Disabled)
1829         return;
1830
1831     RefPtr<TextTrackCue> cue = prpCue;
1832
1833     // Negative duration cues need be treated in the interval tree as
1834     // zero-length cues.
1835     MediaTime endTime = std::max(cue->startMediaTime(), cue->endMediaTime());
1836
1837     CueInterval interval = m_cueTree.createInterval(cue->startMediaTime(), endTime, cue.get());
1838     if (!m_cueTree.contains(interval))
1839         m_cueTree.add(interval);
1840     updateActiveTextTrackCues(currentMediaTime());
1841 }
1842
1843 void HTMLMediaElement::textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue> prpCue)
1844 {
1845     RefPtr<TextTrackCue> cue = prpCue;
1846     // Negative duration cues need to be treated in the interval tree as
1847     // zero-length cues.
1848     MediaTime endTime = std::max(cue->startMediaTime(), cue->endMediaTime());
1849
1850     CueInterval interval = m_cueTree.createInterval(cue->startMediaTime(), endTime, cue.get());
1851     m_cueTree.remove(interval);
1852
1853     // Since the cue will be removed from the media element and likely the
1854     // TextTrack might also be destructed, notifying the region of the cue
1855     // removal shouldn't be done.
1856     if (cue->isRenderable())
1857         toVTTCue(cue.get())->notifyRegionWhenRemovingDisplayTree(false);
1858
1859     size_t index = m_currentlyActiveCues.find(interval);
1860     if (index != notFound) {
1861         cue->setIsActive(false);
1862         m_currentlyActiveCues.remove(index);
1863     }
1864
1865     if (cue->isRenderable())
1866         toVTTCue(cue.get())->removeDisplayTree();
1867     updateActiveTextTrackCues(currentMediaTime());
1868
1869     if (cue->isRenderable())
1870         toVTTCue(cue.get())->notifyRegionWhenRemovingDisplayTree(true);
1871 }
1872
1873 #endif
1874
1875 bool HTMLMediaElement::isSafeToLoadURL(const URL& url, InvalidURLAction actionIfInvalid)
1876 {
1877     if (!url.isValid()) {
1878         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%p) - %s -> FALSE because url is invalid", this, urlForLoggingMedia(url).utf8().data());
1879         return false;
1880     }
1881
1882     Frame* frame = document().frame();
1883     if (!frame || !document().securityOrigin()->canDisplay(url)) {
1884         if (actionIfInvalid == Complain)
1885             FrameLoader::reportLocalLoadFailed(frame, url.stringCenterEllipsizedToLength());
1886         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%p) - %s -> FALSE rejected by SecurityOrigin", this, urlForLoggingMedia(url).utf8().data());
1887         return false;
1888     }
1889
1890     if (!document().contentSecurityPolicy()->allowMediaFromSource(url, isInUserAgentShadowTree())) {
1891         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%p) - %s -> rejected by Content Security Policy", this, urlForLoggingMedia(url).utf8().data());
1892         return false;
1893     }
1894
1895     return true;
1896 }
1897
1898 void HTMLMediaElement::startProgressEventTimer()
1899 {
1900     if (m_progressEventTimer.isActive())
1901         return;
1902
1903     m_previousProgressTime = monotonicallyIncreasingTime();
1904     // 350ms is not magic, it is in the spec!
1905     m_progressEventTimer.startRepeating(0.350);
1906 }
1907
1908 void HTMLMediaElement::waitForSourceChange()
1909 {
1910     LOG(Media, "HTMLMediaElement::waitForSourceChange(%p)", this);
1911
1912     stopPeriodicTimers();
1913     m_loadState = WaitingForSource;
1914
1915     // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
1916     m_networkState = NETWORK_NO_SOURCE;
1917
1918     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1919     setShouldDelayLoadEvent(false);
1920
1921     updateDisplayState();
1922
1923     if (renderer())
1924         renderer()->updateFromElement();
1925 }
1926
1927 void HTMLMediaElement::noneSupported()
1928 {
1929     LOG(Media, "HTMLMediaElement::noneSupported(%p)", this);
1930
1931     stopPeriodicTimers();
1932     m_loadState = WaitingForSource;
1933     m_currentSourceNode = nullptr;
1934
1935     // 4.8.10.5 
1936     // 6 - Reaching this step indicates that the media resource failed to load or that the given 
1937     // URL could not be resolved. In one atomic operation, run the following steps:
1938
1939     // 6.1 - Set the error attribute to a new MediaError object whose code attribute is set to
1940     // MEDIA_ERR_SRC_NOT_SUPPORTED.
1941     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
1942
1943     // 6.2 - Forget the media element's media-resource-specific text tracks.
1944     forgetResourceSpecificTracks();
1945
1946     // 6.3 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
1947     m_networkState = NETWORK_NO_SOURCE;
1948
1949     // 7 - Queue a task to fire a simple event named error at the media element.
1950     scheduleEvent(eventNames().errorEvent);
1951
1952     rejectPendingPlayPromises(DOMError::create("NotSupportedError", "The operation is not supported."));
1953
1954 #if ENABLE(MEDIA_SOURCE)
1955     closeMediaSource();
1956 #endif
1957
1958     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1959     setShouldDelayLoadEvent(false);
1960
1961     // 9 - Abort these steps. Until the load() method is invoked or the src attribute is changed, 
1962     // the element won't attempt to load another resource.
1963
1964     updateDisplayState();
1965
1966     if (renderer())
1967         renderer()->updateFromElement();
1968 }
1969
1970 void HTMLMediaElement::mediaLoadingFailedFatally(MediaPlayer::NetworkState error)
1971 {
1972     LOG(Media, "HTMLMediaElement::mediaLoadingFailedFatally(%p) - error = %d", this, static_cast<int>(error));
1973
1974     // 1 - The user agent should cancel the fetching process.
1975     stopPeriodicTimers();
1976     m_loadState = WaitingForSource;
1977
1978     // 2 - Set the error attribute to a new MediaError object whose code attribute is 
1979     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
1980     if (error == MediaPlayer::NetworkError)
1981         m_error = MediaError::create(MediaError::MEDIA_ERR_NETWORK);
1982     else if (error == MediaPlayer::DecodeError)
1983         m_error = MediaError::create(MediaError::MEDIA_ERR_DECODE);
1984     else
1985         ASSERT_NOT_REACHED();
1986
1987     // 3 - Queue a task to fire a simple event named error at the media element.
1988     scheduleEvent(eventNames().errorEvent);
1989
1990 #if ENABLE(MEDIA_SOURCE)
1991     closeMediaSource();
1992 #endif
1993
1994     // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
1995     // task to fire a simple event called emptied at the element.
1996     m_networkState = NETWORK_EMPTY;
1997     scheduleEvent(eventNames().emptiedEvent);
1998
1999     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
2000     setShouldDelayLoadEvent(false);
2001
2002     // 6 - Abort the overall resource selection algorithm.
2003     m_currentSourceNode = nullptr;
2004
2005 #if PLATFORM(COCOA)
2006     if (is<MediaDocument>(document()))
2007         downcast<MediaDocument>(document()).mediaElementSawUnsupportedTracks();
2008 #endif
2009 }
2010
2011 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
2012 {
2013     LOG(Media, "HTMLMediaElement::cancelPendingEventsAndCallbacks(%p)", this);
2014     m_asyncEventQueue.cancelAllEvents();
2015
2016     for (auto& source : childrenOfType<HTMLSourceElement>(*this))
2017         source.cancelPendingErrorEvent();
2018
2019     rejectPendingPlayPromises(DOMError::create("AbortError", "The operation was aborted."));
2020 }
2021
2022 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
2023 {
2024     beginProcessingMediaPlayerCallback();
2025     setNetworkState(m_player->networkState());
2026     endProcessingMediaPlayerCallback();
2027 }
2028
2029 static void logMediaLoadRequest(Page* page, const String& mediaEngine, const String& errorMessage, bool succeeded)
2030 {
2031     if (!page)
2032         return;
2033
2034     DiagnosticLoggingClient& diagnosticLoggingClient = page->diagnosticLoggingClient();
2035     if (!succeeded) {
2036         diagnosticLoggingClient.logDiagnosticMessageWithResult(DiagnosticLoggingKeys::mediaLoadingFailedKey(), errorMessage, DiagnosticLoggingResultFail, ShouldSample::No);
2037         return;
2038     }
2039
2040     diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::mediaLoadedKey(), mediaEngine, ShouldSample::No);
2041
2042     if (!page->hasSeenAnyMediaEngine())
2043         diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsAtLeastOneMediaEngineKey(), emptyString(), ShouldSample::No);
2044
2045     if (!page->hasSeenMediaEngine(mediaEngine))
2046         diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsMediaEngineKey(), mediaEngine, ShouldSample::No);
2047
2048     page->sawMediaEngine(mediaEngine);
2049 }
2050
2051 static String stringForNetworkState(MediaPlayer::NetworkState state)
2052 {
2053     switch (state) {
2054     case MediaPlayer::Empty: return ASCIILiteral("Empty");
2055     case MediaPlayer::Idle: return ASCIILiteral("Idle");
2056     case MediaPlayer::Loading: return ASCIILiteral("Loading");
2057     case MediaPlayer::Loaded: return ASCIILiteral("Loaded");
2058     case MediaPlayer::FormatError: return ASCIILiteral("FormatError");
2059     case MediaPlayer::NetworkError: return ASCIILiteral("NetworkError");
2060     case MediaPlayer::DecodeError: return ASCIILiteral("DecodeError");
2061     default: return emptyString();
2062     }
2063 }
2064
2065 void HTMLMediaElement::mediaLoadingFailed(MediaPlayer::NetworkState error)
2066 {
2067     stopPeriodicTimers();
2068     
2069     // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
2070     // <source> children, schedule the next one
2071     if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
2072         
2073         // resource selection algorithm
2074         // 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.
2075         if (m_currentSourceNode)
2076             m_currentSourceNode->scheduleErrorEvent();
2077         else
2078             LOG(Media, "HTMLMediaElement::setNetworkState(%p) - error event not sent, <source> was removed", this);
2079         
2080         // 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.
2081         
2082         // 9.Otherwise.11 - Forget the media element's media-resource-specific tracks.
2083         forgetResourceSpecificTracks();
2084
2085         if (havePotentialSourceChild()) {
2086             LOG(Media, "HTMLMediaElement::setNetworkState(%p) - scheduling next <source>", this);
2087             scheduleNextSourceChild();
2088         } else {
2089             LOG(Media, "HTMLMediaElement::setNetworkState(%p) - no more <source> elements, waiting", this);
2090             waitForSourceChange();
2091         }
2092         
2093         return;
2094     }
2095     
2096     if ((error == MediaPlayer::NetworkError && m_readyState >= HAVE_METADATA) || error == MediaPlayer::DecodeError)
2097         mediaLoadingFailedFatally(error);
2098     else if ((error == MediaPlayer::FormatError || error == MediaPlayer::NetworkError) && m_loadState == LoadingFromSrcAttr)
2099         noneSupported();
2100     
2101     updateDisplayState();
2102     if (hasMediaControls()) {
2103         mediaControls()->reset();
2104         mediaControls()->reportedError();
2105     }
2106
2107     logMediaLoadRequest(document().page(), String(), stringForNetworkState(error), false);
2108
2109     m_mediaSession->clientCharacteristicsChanged();
2110 }
2111
2112 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
2113 {
2114     LOG(Media, "HTMLMediaElement::setNetworkState(%p) - new state = %d, current state = %d", this, static_cast<int>(state), static_cast<int>(m_networkState));
2115
2116     if (state == MediaPlayer::Empty) {
2117         // Just update the cached state and leave, we can't do anything.
2118         m_networkState = NETWORK_EMPTY;
2119         return;
2120     }
2121
2122     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
2123         mediaLoadingFailed(state);
2124         return;
2125     }
2126
2127     if (state == MediaPlayer::Idle) {
2128         if (m_networkState > NETWORK_IDLE) {
2129             changeNetworkStateFromLoadingToIdle();
2130             setShouldDelayLoadEvent(false);
2131         } else {
2132             m_networkState = NETWORK_IDLE;
2133         }
2134     }
2135
2136     if (state == MediaPlayer::Loading) {
2137         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
2138             startProgressEventTimer();
2139         m_networkState = NETWORK_LOADING;
2140     }
2141
2142     if (state == MediaPlayer::Loaded) {
2143         if (m_networkState != NETWORK_IDLE)
2144             changeNetworkStateFromLoadingToIdle();
2145         m_completelyLoaded = true;
2146     }
2147
2148     if (hasMediaControls())
2149         mediaControls()->updateStatusDisplay();
2150 }
2151
2152 void HTMLMediaElement::changeNetworkStateFromLoadingToIdle()
2153 {
2154     m_progressEventTimer.stop();
2155     if (hasMediaControls() && m_player->didLoadingProgress())
2156         mediaControls()->bufferingProgressed();
2157
2158     // Schedule one last progress event so we guarantee that at least one is fired
2159     // for files that load very quickly.
2160     scheduleEvent(eventNames().progressEvent);
2161     scheduleEvent(eventNames().suspendEvent);
2162     m_networkState = NETWORK_IDLE;
2163 }
2164
2165 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
2166 {
2167     beginProcessingMediaPlayerCallback();
2168
2169     setReadyState(m_player->readyState());
2170
2171     endProcessingMediaPlayerCallback();
2172 }
2173
2174 bool HTMLMediaElement::canTransitionFromAutoplayToPlay() const
2175 {
2176     return isAutoplaying()
2177         && paused()
2178         && autoplay()
2179         && !pausedForUserInteraction()
2180         && !document().isSandboxed(SandboxAutomaticFeatures)
2181         && mediaSession().playbackPermitted(*this);
2182 }
2183
2184 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
2185 {
2186     LOG(Media, "HTMLMediaElement::setReadyState(%p) - new state = %d, current state = %d,", this, static_cast<int>(state), static_cast<int>(m_readyState));
2187
2188     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
2189     bool wasPotentiallyPlaying = potentiallyPlaying();
2190
2191     ReadyState oldState = m_readyState;
2192     ReadyState newState = static_cast<ReadyState>(state);
2193
2194 #if ENABLE(VIDEO_TRACK)
2195     bool tracksAreReady = textTracksAreReady();
2196
2197     if (newState == oldState && m_tracksAreReady == tracksAreReady)
2198         return;
2199
2200     m_tracksAreReady = tracksAreReady;
2201 #else
2202     if (newState == oldState)
2203         return;
2204     bool tracksAreReady = true;
2205 #endif
2206     
2207     if (tracksAreReady)
2208         m_readyState = newState;
2209     else {
2210         // If a media file has text tracks the readyState may not progress beyond HAVE_FUTURE_DATA until
2211         // the text tracks are ready, regardless of the state of the media file.
2212         if (newState <= HAVE_METADATA)
2213             m_readyState = newState;
2214         else
2215             m_readyState = HAVE_CURRENT_DATA;
2216     }
2217     
2218     if (oldState > m_readyStateMaximum)
2219         m_readyStateMaximum = oldState;
2220
2221     if (m_networkState == NETWORK_EMPTY)
2222         return;
2223
2224     if (m_seeking) {
2225         // 4.8.10.9, step 11
2226         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
2227             scheduleEvent(eventNames().waitingEvent);
2228
2229         // 4.8.10.10 step 14 & 15.
2230         if (!m_player->seeking() && m_readyState >= HAVE_CURRENT_DATA)
2231             finishSeek();
2232     } else {
2233         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
2234             // 4.8.10.8
2235             invalidateCachedTime();
2236             scheduleTimeupdateEvent(false);
2237             scheduleEvent(eventNames().waitingEvent);
2238         }
2239     }
2240
2241     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
2242         prepareMediaFragmentURI();
2243         scheduleEvent(eventNames().durationchangeEvent);
2244         scheduleResizeEvent();
2245         scheduleEvent(eventNames().loadedmetadataEvent);
2246 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
2247         if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent))
2248             enqueuePlaybackTargetAvailabilityChangedEvent();
2249 #endif
2250         m_initiallyMuted = m_volume < 0.05 || muted();
2251
2252         if (hasMediaControls())
2253             mediaControls()->loadedMetadata();
2254         if (renderer())
2255             renderer()->updateFromElement();
2256
2257         if (is<MediaDocument>(document()))
2258             downcast<MediaDocument>(document()).mediaElementNaturalSizeChanged(expandedIntSize(m_player->naturalSize()));
2259
2260         logMediaLoadRequest(document().page(), m_player->engineDescription(), String(), true);
2261
2262 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
2263         updateMediaState(UpdateMediaState::Asynchronously);
2264 #endif
2265
2266         m_mediaSession->clientCharacteristicsChanged();
2267     }
2268
2269     bool shouldUpdateDisplayState = false;
2270
2271     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
2272         m_haveFiredLoadedData = true;
2273         shouldUpdateDisplayState = true;
2274         scheduleEvent(eventNames().loadeddataEvent);
2275         setShouldDelayLoadEvent(false);
2276         applyMediaFragmentURI();
2277     }
2278
2279     bool isPotentiallyPlaying = potentiallyPlaying();
2280     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) {
2281         scheduleEvent(eventNames().canplayEvent);
2282         if (isPotentiallyPlaying)
2283             scheduleNotifyAboutPlaying();
2284         shouldUpdateDisplayState = true;
2285     }
2286
2287     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && tracksAreReady) {
2288         if (oldState <= HAVE_CURRENT_DATA)
2289             scheduleEvent(eventNames().canplayEvent);
2290
2291         scheduleEvent(eventNames().canplaythroughEvent);
2292
2293         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
2294             scheduleNotifyAboutPlaying();
2295
2296         if (canTransitionFromAutoplayToPlay()) {
2297             m_paused = false;
2298             invalidateCachedTime();
2299             scheduleEvent(eventNames().playEvent);
2300             scheduleNotifyAboutPlaying();
2301         }
2302
2303         shouldUpdateDisplayState = true;
2304     }
2305
2306     if (shouldUpdateDisplayState) {
2307         updateDisplayState();
2308         if (hasMediaControls()) {
2309             mediaControls()->refreshClosedCaptionsButtonVisibility();
2310             mediaControls()->updateStatusDisplay();
2311         }
2312     }
2313
2314     updatePlayState();
2315     updateMediaController();
2316 #if ENABLE(VIDEO_TRACK)
2317     updateActiveTextTrackCues(currentMediaTime());
2318 #endif
2319 }
2320
2321 #if ENABLE(ENCRYPTED_MEDIA)
2322 void HTMLMediaElement::mediaPlayerKeyAdded(MediaPlayer*, const String& keySystem, const String& sessionId)
2323 {
2324     Ref<Event> event = MediaKeyEvent::create(eventNames().webkitkeyaddedEvent, keySystem, sessionId, nullptr, nullptr, emptyString(), nullptr, 0);
2325     event->setTarget(this);
2326     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2327 }
2328
2329 void HTMLMediaElement::mediaPlayerKeyError(MediaPlayer*, const String& keySystem, const String& sessionId, MediaPlayerClient::MediaKeyErrorCode errorCode, unsigned short systemCode)
2330 {
2331     MediaKeyError::Code mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
2332     switch (errorCode) {
2333     case MediaPlayerClient::UnknownError:
2334         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
2335         break;
2336     case MediaPlayerClient::ClientError:
2337         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_CLIENT;
2338         break;
2339     case MediaPlayerClient::ServiceError:
2340         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_SERVICE;
2341         break;
2342     case MediaPlayerClient::OutputError:
2343         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_OUTPUT;
2344         break;
2345     case MediaPlayerClient::HardwareChangeError:
2346         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_HARDWARECHANGE;
2347         break;
2348     case MediaPlayerClient::DomainError:
2349         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_DOMAIN;
2350         break;
2351     }
2352
2353     Ref<Event> event = MediaKeyEvent::create(eventNames().webkitkeyerrorEvent, keySystem, sessionId, nullptr, nullptr, emptyString(), MediaKeyError::create(mediaKeyErrorCode), systemCode);
2354     event->setTarget(this);
2355     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2356 }
2357
2358 void HTMLMediaElement::mediaPlayerKeyMessage(MediaPlayer*, const String& keySystem, const String& sessionId, const unsigned char* message, unsigned messageLength, const URL& defaultURL)
2359 {
2360     Ref<Event> event = MediaKeyEvent::create(eventNames().webkitkeymessageEvent, keySystem, sessionId, nullptr, Uint8Array::create(message, messageLength), defaultURL, nullptr, 0);
2361     event->setTarget(this);
2362     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2363 }
2364
2365 bool HTMLMediaElement::mediaPlayerKeyNeeded(MediaPlayer*, const String& keySystem, const String& sessionId, const unsigned char* initData, unsigned initDataLength)
2366 {
2367     if (!hasEventListeners(eventNames().webkitneedkeyEvent)) {
2368         m_error = MediaError::create(MediaError::MEDIA_ERR_ENCRYPTED);
2369         scheduleEvent(eventNames().errorEvent);
2370         return false;
2371     }
2372
2373     Ref<Event> event = MediaKeyEvent::create(eventNames().webkitneedkeyEvent, keySystem, sessionId, Uint8Array::create(initData, initDataLength), nullptr, emptyString(), nullptr, 0);
2374     event->setTarget(this);
2375     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2376     return true;
2377 }
2378 #endif
2379
2380 #if ENABLE(ENCRYPTED_MEDIA_V2)
2381 RefPtr<ArrayBuffer> HTMLMediaElement::mediaPlayerCachedKeyForKeyId(const String& keyId) const
2382 {
2383     return m_mediaKeys ? m_mediaKeys->cachedKeyForKeyId(keyId) : nullptr;
2384 }
2385
2386 bool HTMLMediaElement::mediaPlayerKeyNeeded(MediaPlayer*, Uint8Array* initData)
2387 {
2388     if (!hasEventListeners("webkitneedkey")) {
2389         m_error = MediaError::create(MediaError::MEDIA_ERR_ENCRYPTED);
2390         scheduleEvent(eventNames().errorEvent);
2391         return false;
2392     }
2393
2394     auto event = MediaKeyNeededEvent::create(eventNames().webkitneedkeyEvent, initData);
2395     event->setTarget(this);
2396     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2397
2398     return true;
2399 }
2400
2401 String HTMLMediaElement::mediaPlayerMediaKeysStorageDirectory() const
2402 {
2403     Settings* settings = document().settings();
2404     if (!settings)
2405         return emptyString();
2406
2407     String storageDirectory = settings->mediaKeysStorageDirectory();
2408     if (storageDirectory.isEmpty())
2409         return emptyString();
2410
2411     SecurityOrigin* origin = document().securityOrigin();
2412     if (!origin)
2413         return emptyString();
2414
2415     return pathByAppendingComponent(storageDirectory, origin->databaseIdentifier());
2416 }
2417
2418 void HTMLMediaElement::setMediaKeys(MediaKeys* mediaKeys)
2419 {
2420     if (m_mediaKeys == mediaKeys)
2421         return;
2422
2423     if (m_mediaKeys)
2424         m_mediaKeys->setMediaElement(0);
2425     m_mediaKeys = mediaKeys;
2426     if (m_mediaKeys)
2427         m_mediaKeys->setMediaElement(this);
2428 }
2429
2430 void HTMLMediaElement::keyAdded()
2431 {
2432     if (m_player)
2433         m_player->keyAdded();
2434 }
2435 #endif
2436
2437 void HTMLMediaElement::progressEventTimerFired()
2438 {
2439     ASSERT(m_player);
2440     if (m_networkState != NETWORK_LOADING)
2441         return;
2442
2443     double time = monotonicallyIncreasingTime();
2444     double timedelta = time - m_previousProgressTime;
2445
2446     if (m_player->didLoadingProgress()) {
2447         scheduleEvent(eventNames().progressEvent);
2448         m_previousProgressTime = time;
2449         m_sentStalledEvent = false;
2450         if (renderer())
2451             renderer()->updateFromElement();
2452         if (hasMediaControls())
2453             mediaControls()->bufferingProgressed();
2454     } else if (timedelta > 3.0 && !m_sentStalledEvent) {
2455         scheduleEvent(eventNames().stalledEvent);
2456         m_sentStalledEvent = true;
2457         setShouldDelayLoadEvent(false);
2458     }
2459 }
2460
2461 void HTMLMediaElement::rewind(double timeDelta)
2462 {
2463     LOG(Media, "HTMLMediaElement::rewind(%p) - %f", this, timeDelta);
2464     setCurrentTime(std::max(currentMediaTime() - MediaTime::createWithDouble(timeDelta), minTimeSeekable()));
2465 }
2466
2467 void HTMLMediaElement::returnToRealtime()
2468 {
2469     LOG(Media, "HTMLMediaElement::returnToRealtime(%p)", this);
2470     setCurrentTime(maxTimeSeekable());
2471 }
2472
2473 void HTMLMediaElement::addPlayedRange(const MediaTime& start, const MediaTime& end)
2474 {
2475     LOG(Media, "HTMLMediaElement::addPlayedRange(%p) - [%s, %s]", this, toString(start).utf8().data(), toString(end).utf8().data());
2476     if (!m_playedTimeRanges)
2477         m_playedTimeRanges = TimeRanges::create();
2478     m_playedTimeRanges->ranges().add(start, end);
2479 }  
2480
2481 bool HTMLMediaElement::supportsScanning() const
2482 {
2483     return m_player ? m_player->supportsScanning() : false;
2484 }
2485
2486 void HTMLMediaElement::prepareToPlay()
2487 {
2488     LOG(Media, "HTMLMediaElement::prepareToPlay(%p)", this);
2489     if (m_havePreparedToPlay)
2490         return;
2491     m_havePreparedToPlay = true;
2492     m_player->prepareToPlay();
2493 }
2494
2495 void HTMLMediaElement::fastSeek(double time)
2496 {
2497     fastSeek(MediaTime::createWithDouble(time));
2498 }
2499
2500 void HTMLMediaElement::fastSeek(const MediaTime& time)
2501 {
2502     LOG(Media, "HTMLMediaElement::fastSeek(%p) - %s", this, toString(time).utf8().data());
2503     // 4.7.10.9 Seeking
2504     // 9. If the approximate-for-speed flag is set, adjust the new playback position to a value that will
2505     // allow for playback to resume promptly. If new playback position before this step is before current
2506     // playback position, then the adjusted new playback position must also be before the current playback
2507     // position. Similarly, if the new playback position before this step is after current playback position,
2508     // then the adjusted new playback position must also be after the current playback position.
2509     refreshCachedTime();
2510     MediaTime delta = time - currentMediaTime();
2511     MediaTime negativeTolerance = delta >= MediaTime::zeroTime() ? delta : MediaTime::positiveInfiniteTime();
2512     MediaTime positiveTolerance = delta < MediaTime::zeroTime() ? -delta : MediaTime::positiveInfiniteTime();
2513
2514     seekWithTolerance(time, negativeTolerance, positiveTolerance, true);
2515 }
2516
2517 void HTMLMediaElement::seek(const MediaTime& time)
2518 {
2519     LOG(Media, "HTMLMediaElement::seek(%p) - %s", this, toString(time).utf8().data());
2520     seekWithTolerance(time, MediaTime::zeroTime(), MediaTime::zeroTime(), true);
2521 }
2522
2523 void HTMLMediaElement::seekInternal(const MediaTime& time)
2524 {
2525     LOG(Media, "HTMLMediaElement::seekInternal(%p) - %s", this, toString(time).utf8().data());
2526     seekWithTolerance(time, MediaTime::zeroTime(), MediaTime::zeroTime(), false);
2527 }
2528
2529 void HTMLMediaElement::seekWithTolerance(const MediaTime& inTime, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance, bool fromDOM)
2530 {
2531     // 4.8.10.9 Seeking
2532     MediaTime time = inTime;
2533
2534     // 1 - Set the media element's show poster flag to false.
2535     setDisplayMode(Video);
2536
2537     // 2 - If the media element's readyState is HAVE_NOTHING, abort these steps.
2538     if (m_readyState == HAVE_NOTHING || !m_player)
2539         return;
2540
2541     // If the media engine has been told to postpone loading data, let it go ahead now.
2542     if (m_preload < MediaPlayer::Auto && m_readyState < HAVE_FUTURE_DATA)
2543         prepareToPlay();
2544
2545     // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
2546     refreshCachedTime();
2547     MediaTime now = currentMediaTime();
2548
2549     // 3 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
2550     // already running. Abort that other instance of the algorithm without waiting for the step that
2551     // it is running to complete.
2552     if (m_seekTaskQueue.hasPendingTasks()) {
2553         LOG(Media, "HTMLMediaElement::seekWithTolerance(%p) - cancelling pending seeks", this);
2554         m_seekTaskQueue.cancelAllTasks();
2555         if (m_pendingSeek) {
2556             now = m_pendingSeek->now;
2557             m_pendingSeek = nullptr;
2558         }
2559         m_pendingSeekType = NoSeek;
2560     }
2561
2562     // 4 - Set the seeking IDL attribute to true.
2563     // The flag will be cleared when the engine tells us the time has actually changed.
2564     m_seeking = true;
2565     if (m_playing) {
2566         if (m_lastSeekTime < now)
2567             addPlayedRange(m_lastSeekTime, now);
2568     }
2569     m_lastSeekTime = time;
2570
2571     // 5 - If the seek was in response to a DOM method call or setting of an IDL attribute, then continue
2572     // the script. The remainder of these steps must be run asynchronously.
2573     m_pendingSeek = std::make_unique<PendingSeek>(now, time, negativeTolerance, positiveTolerance);
2574     if (fromDOM) {
2575         LOG(Media, "HTMLMediaElement::seekWithTolerance(%p) - enqueuing seek from %s to %s", this, toString(now).utf8().data(), toString(time).utf8().data());
2576         m_seekTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::seekTask, this));
2577     } else
2578         seekTask();
2579 }
2580
2581 void HTMLMediaElement::seekTask()
2582 {
2583     LOG(Media, "HTMLMediaElement::seekTask(%p)", this);
2584
2585     if (!m_player) {
2586         clearSeeking();
2587         return;
2588     }
2589
2590     ASSERT(m_pendingSeek);
2591     MediaTime now = m_pendingSeek->now;
2592     MediaTime time = m_pendingSeek->targetTime;
2593     MediaTime negativeTolerance = m_pendingSeek->negativeTolerance;
2594     MediaTime positiveTolerance = m_pendingSeek->positiveTolerance;
2595     m_pendingSeek = nullptr;
2596
2597     // 6 - If the new playback position is later than the end of the media resource, then let it be the end 
2598     // of the media resource instead.
2599     time = std::min(time, durationMediaTime());
2600
2601     // 7 - If the new playback position is less than the earliest possible position, let it be that position instead.
2602     MediaTime earliestTime = m_player->startTime();
2603     time = std::max(time, earliestTime);
2604
2605     // Ask the media engine for the time value in the movie's time scale before comparing with current time. This
2606     // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's
2607     // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
2608     // not generate a timechanged callback. This means m_seeking will never be cleared and we will never 
2609     // fire a 'seeked' event.
2610 #if !LOG_DISABLED
2611     MediaTime mediaTime = m_player->mediaTimeForTimeValue(time);
2612     if (time != mediaTime)
2613         LOG(Media, "HTMLMediaElement::seekTask(%p) - %s - media timeline equivalent is %s", this, toString(time).utf8().data(), toString(mediaTime).utf8().data());
2614 #endif
2615     time = m_player->mediaTimeForTimeValue(time);
2616
2617     // 8 - If the (possibly now changed) new playback position is not in one of the ranges given in the
2618     // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute 
2619     // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
2620     // attribute then set the seeking IDL attribute to false and abort these steps.
2621     RefPtr<TimeRanges> seekableRanges = seekable();
2622     bool noSeekRequired = !seekableRanges->length();
2623
2624     // Short circuit seeking to the current time by just firing the events if no seek is required.
2625     // Don't skip calling the media engine if 1) we are in poster mode (because a seek should always cancel
2626     // poster display), or 2) if there is a pending fast seek, or 3) if this seek is not an exact seek
2627     SeekType thisSeekType = (negativeTolerance == MediaTime::zeroTime() && positiveTolerance == MediaTime::zeroTime()) ? Precise : Fast;
2628     if (!noSeekRequired && time == now && thisSeekType == Precise && m_pendingSeekType != Fast && displayMode() != Poster)
2629         noSeekRequired = true;
2630
2631 #if ENABLE(MEDIA_SOURCE)
2632     // Always notify the media engine of a seek if the source is not closed. This ensures that the source is
2633     // always in a flushed state when the 'seeking' event fires.
2634     if (m_mediaSource && !m_mediaSource->isClosed())
2635         noSeekRequired = false;
2636 #endif
2637
2638     if (noSeekRequired) {
2639         LOG(Media, "HTMLMediaElement::seekTask(%p) - seek to %s ignored", this, toString(time).utf8().data());
2640         if (time == now) {
2641             scheduleEvent(eventNames().seekingEvent);
2642             scheduleTimeupdateEvent(false);
2643             scheduleEvent(eventNames().seekedEvent);
2644         }
2645         clearSeeking();
2646         return;
2647     }
2648     time = seekableRanges->ranges().nearest(time);
2649
2650     m_sentEndEvent = false;
2651     m_lastSeekTime = time;
2652     m_pendingSeekType = thisSeekType;
2653     m_seeking = true;
2654
2655     // 10 - Queue a task to fire a simple event named seeking at the element.
2656     scheduleEvent(eventNames().seekingEvent);
2657
2658     // 11 - Set the current playback position to the given new playback position
2659     m_player->seekWithTolerance(time, negativeTolerance, positiveTolerance);
2660
2661     // 12 - Wait until the user agent has established whether or not the media data for the new playback
2662     // position is available, and, if it is, until it has decoded enough data to play back that position.
2663     // 13 - Await a stable state. The synchronous section consists of all the remaining steps of this algorithm.
2664 }
2665
2666 void HTMLMediaElement::clearSeeking()
2667 {
2668     m_seeking = false;
2669     m_pendingSeekType = NoSeek;
2670     invalidateCachedTime();
2671 }
2672
2673 void HTMLMediaElement::finishSeek()
2674 {
2675     // 4.8.10.9 Seeking
2676     // 14 - Set the seeking IDL attribute to false.
2677     clearSeeking();
2678
2679     LOG(Media, "HTMLMediaElement::finishSeek(%p) - current time = %s", this, toString(currentMediaTime()).utf8().data());
2680
2681     // 15 - Run the time maches on steps.
2682     // Handled by mediaPlayerTimeChanged().
2683
2684     // 16 - Queue a task to fire a simple event named timeupdate at the element.
2685     scheduleEvent(eventNames().timeupdateEvent);
2686
2687     // 17 - Queue a task to fire a simple event named seeked at the element.
2688     scheduleEvent(eventNames().seekedEvent);
2689
2690 #if ENABLE(MEDIA_SOURCE)
2691     if (m_mediaSource)
2692         m_mediaSource->monitorSourceBuffers();
2693 #endif
2694 }
2695
2696 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
2697 {
2698     return m_readyState;
2699 }
2700
2701 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
2702 {
2703     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
2704 }
2705
2706 bool HTMLMediaElement::hasAudio() const
2707 {
2708     return m_player ? m_player->hasAudio() : false;
2709 }
2710
2711 bool HTMLMediaElement::seeking() const
2712 {
2713     return m_seeking;
2714 }
2715
2716 void HTMLMediaElement::refreshCachedTime() const
2717 {
2718     if (!m_player)
2719         return;
2720
2721     m_cachedTime = m_player->currentTime();
2722     if (!m_cachedTime) {
2723         // Do not use m_cachedTime until the media engine returns a non-zero value because we can't 
2724         // estimate current time until playback actually begins. 
2725         invalidateCachedTime(); 
2726         return; 
2727     } 
2728
2729     m_clockTimeAtLastCachedTimeUpdate = monotonicallyIncreasingTime();
2730 }
2731
2732 void HTMLMediaElement::invalidateCachedTime() const
2733 {
2734     m_cachedTime = MediaTime::invalidTime();
2735     if (!m_player || !m_player->maximumDurationToCacheMediaTime())
2736         return;
2737
2738 #if !LOG_DISABLED
2739     if (m_cachedTime.isValid())
2740         LOG(Media, "HTMLMediaElement::invalidateCachedTime(%p)", this);
2741 #endif
2742
2743     // Don't try to cache movie time when playback first starts as the time reported by the engine
2744     // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
2745     // too early.
2746     static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
2747
2748     m_minimumClockTimeToUpdateCachedTime = monotonicallyIncreasingTime() + minimumTimePlayingBeforeCacheSnapshot;
2749 }
2750
2751 // playback state
2752 double HTMLMediaElement::currentTime() const
2753 {
2754     return currentMediaTime().toDouble();
2755 }
2756
2757 MediaTime HTMLMediaElement::currentMediaTime() const
2758 {
2759 #if LOG_CACHED_TIME_WARNINGS
2760     static const MediaTime minCachedDeltaForWarning = MediaTime::create(1, 100);
2761 #endif
2762
2763     if (!m_player)
2764         return MediaTime::zeroTime();
2765
2766     if (m_seeking) {
2767         LOG(Media, "HTMLMediaElement::currentTime(%p) - seeking, returning %s", this, toString(m_lastSeekTime).utf8().data());
2768         return m_lastSeekTime;
2769     }
2770
2771     if (m_cachedTime.isValid() && m_paused) {
2772 #if LOG_CACHED_TIME_WARNINGS
2773         MediaTime delta = m_cachedTime - m_player->currentTime();
2774         if (delta > minCachedDeltaForWarning)
2775             LOG(Media, "HTMLMediaElement::currentTime(%p) - WARNING, cached time is %s seconds off of media time when paused", this, toString(delta).utf8().data());
2776 #endif
2777         return m_cachedTime;
2778     }
2779
2780     // Is it too soon use a cached time?
2781     double now = monotonicallyIncreasingTime();
2782     double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
2783
2784     if (maximumDurationToCacheMediaTime && m_cachedTime.isValid() && !m_paused && now > m_minimumClockTimeToUpdateCachedTime) {
2785         double clockDelta = now - m_clockTimeAtLastCachedTimeUpdate;
2786
2787         // Not too soon, use the cached time only if it hasn't expired.
2788         if (clockDelta < maximumDurationToCacheMediaTime) {
2789             MediaTime adjustedCacheTime = m_cachedTime + MediaTime::createWithDouble(effectivePlaybackRate() * clockDelta);
2790
2791 #if LOG_CACHED_TIME_WARNINGS
2792             MediaTime delta = adjustedCacheTime - m_player->currentTime();
2793             if (delta > minCachedDeltaForWarning)
2794                 LOG(Media, "HTMLMediaElement::currentTime(%p) - WARNING, cached time is %f seconds off of media time when playing", this, delta);
2795 #endif
2796             return adjustedCacheTime;
2797         }
2798     }
2799
2800 #if LOG_CACHED_TIME_WARNINGS
2801     if (maximumDurationToCacheMediaTime && now > m_minimumClockTimeToUpdateCachedTime && m_cachedTime != MediaPlayer::invalidTime()) {
2802         double clockDelta = now - m_clockTimeAtLastCachedTimeUpdate;
2803         MediaTime delta = m_cachedTime + MediaTime::createWithDouble(effectivePlaybackRate() * clockDelta) - m_player->currentTime();
2804         LOG(Media, "HTMLMediaElement::currentTime(%p) - cached time was %s seconds off of media time when it expired", this, toString(delta).utf8().data());
2805     }
2806 #endif
2807
2808     refreshCachedTime();
2809
2810     if (m_cachedTime.isInvalid())
2811         return MediaTime::zeroTime();
2812     
2813     return m_cachedTime;
2814 }
2815
2816 void HTMLMediaElement::setCurrentTime(double time)
2817 {
2818     setCurrentTime(MediaTime::createWithDouble(time));
2819 }
2820
2821 void HTMLMediaElement::setCurrentTime(const MediaTime& time)
2822 {
2823     if (m_mediaController)
2824         return;
2825
2826     seekInternal(time);
2827 }
2828
2829 void HTMLMediaElement::setCurrentTime(double time, ExceptionCode& ec)
2830 {
2831     // On setting, if the media element has a current media controller, then the user agent must
2832     // throw an InvalidStateError exception
2833     if (m_mediaController) {
2834         ec = INVALID_STATE_ERR;
2835         return;
2836     }
2837
2838     seek(MediaTime::createWithDouble(time));
2839 }
2840
2841 double HTMLMediaElement::duration() const
2842 {
2843     return durationMediaTime().toDouble();
2844 }
2845
2846 MediaTime HTMLMediaElement::durationMediaTime() const
2847 {
2848     if (m_player && m_readyState >= HAVE_METADATA)
2849         return m_player->duration();
2850
2851     return MediaTime::invalidTime();
2852 }
2853
2854 bool HTMLMediaElement::paused() const
2855 {
2856     // As of this writing, JavaScript garbage collection calls this function directly. In the past
2857     // we had problems where this was called on an object after a bad cast. The assertion below
2858     // made our regression test detect the problem, so we should keep it because of that. But note
2859     // that the value of the assertion relies on the compiler not being smart enough to know that
2860     // isHTMLUnknownElement is guaranteed to return false for an HTMLMediaElement.
2861     ASSERT(!isHTMLUnknownElement());
2862
2863     return m_paused;
2864 }
2865
2866 double HTMLMediaElement::defaultPlaybackRate() const
2867 {
2868 #if ENABLE(MEDIA_STREAM)
2869     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2870     // "defaultPlaybackRate" - On setting: ignored. On getting: return 1.0
2871     // A MediaStream is not seekable. Therefore, this attribute must always have the
2872     // value 1.0 and any attempt to alter it must be ignored. Note that this also means
2873     // that the ratechange event will not fire.
2874     if (m_mediaStreamSrcObject)
2875         return 1;
2876 #endif
2877
2878     return m_defaultPlaybackRate;
2879 }
2880
2881 void HTMLMediaElement::setDefaultPlaybackRate(double rate)
2882 {
2883 #if ENABLE(MEDIA_STREAM)
2884     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2885     // "defaultPlaybackRate" - On setting: ignored. On getting: return 1.0
2886     // A MediaStream is not seekable. Therefore, this attribute must always have the
2887     // value 1.0 and any attempt to alter it must be ignored. Note that this also means
2888     // that the ratechange event will not fire.
2889     if (m_mediaStreamSrcObject)
2890         return;
2891 #endif
2892
2893     if (m_defaultPlaybackRate != rate) {
2894         LOG(Media, "HTMLMediaElement::setDefaultPlaybackRate(%p) - %f", this, rate);
2895         m_defaultPlaybackRate = rate;
2896         scheduleEvent(eventNames().ratechangeEvent);
2897     }
2898 }
2899
2900 double HTMLMediaElement::effectivePlaybackRate() const
2901 {
2902     return m_mediaController ? m_mediaController->playbackRate() : m_reportedPlaybackRate;
2903 }
2904
2905 double HTMLMediaElement::requestedPlaybackRate() const
2906 {
2907     return m_mediaController ? m_mediaController->playbackRate() : m_requestedPlaybackRate;
2908 }
2909
2910 double HTMLMediaElement::playbackRate() const
2911 {
2912 #if ENABLE(MEDIA_STREAM)
2913     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2914     // "playbackRate" - A MediaStream is not seekable. Therefore, this attribute must always
2915     // have the value 1.0 and any attempt to alter it must be ignored. Note that this also
2916     // means that the ratechange event will not fire.
2917     if (m_mediaStreamSrcObject)
2918         return 1;
2919 #endif
2920
2921     return m_requestedPlaybackRate;
2922 }
2923
2924 void HTMLMediaElement::setPlaybackRate(double rate)
2925 {
2926     LOG(Media, "HTMLMediaElement::setPlaybackRate(%p) - %f", this, rate);
2927
2928 #if ENABLE(MEDIA_STREAM)
2929     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2930     // "playbackRate" - A MediaStream is not seekable. Therefore, this attribute must always
2931     // have the value 1.0 and any attempt to alter it must be ignored. Note that this also
2932     // means that the ratechange event will not fire.
2933     if (m_mediaStreamSrcObject)
2934         return;
2935 #endif
2936
2937     if (m_player && potentiallyPlaying() && m_player->rate() != rate && !m_mediaController)
2938         m_player->setRate(rate);
2939
2940     if (m_requestedPlaybackRate != rate) {
2941         m_reportedPlaybackRate = m_requestedPlaybackRate = rate;
2942         invalidateCachedTime();
2943         scheduleEvent(eventNames().ratechangeEvent);
2944     }
2945 }
2946
2947 void HTMLMediaElement::updatePlaybackRate()
2948 {
2949     double requestedRate = requestedPlaybackRate();
2950     if (m_player && potentiallyPlaying() && m_player->rate() != requestedRate)
2951         m_player->setRate(requestedRate);
2952 }
2953
2954 bool HTMLMediaElement::webkitPreservesPitch() const
2955 {
2956     return m_webkitPreservesPitch;
2957 }
2958
2959 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
2960 {
2961     LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%p) - %s", this, boolString(preservesPitch));
2962
2963     m_webkitPreservesPitch = preservesPitch;
2964     
2965     if (!m_player)
2966         return;
2967
2968     m_player->setPreservesPitch(preservesPitch);
2969 }
2970
2971 bool HTMLMediaElement::ended() const
2972 {
2973 #if ENABLE(MEDIA_STREAM)
2974     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2975     // When the MediaStream state moves from the active to the inactive state, the User Agent
2976     // must raise an ended event on the HTMLMediaElement and set its ended attribute to true.
2977     if (m_mediaStreamSrcObject && m_player && m_player->ended())
2978         return true;
2979 #endif
2980
2981     // 4.8.10.8 Playing the media resource
2982     // The ended attribute must return true if the media element has ended 
2983     // playback and the direction of playback is forwards, and false otherwise.
2984     return endedPlayback() && requestedPlaybackRate() > 0;
2985 }
2986
2987 bool HTMLMediaElement::autoplay() const
2988 {
2989     return fastHasAttribute(autoplayAttr);
2990 }
2991
2992 String HTMLMediaElement::preload() const
2993 {
2994 #if ENABLE(MEDIA_STREAM)
2995     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2996     // "preload" - On getting: none. On setting: ignored.
2997     if (m_mediaStreamSrcObject)
2998         return ASCIILiteral("none");
2999 #endif
3000
3001     switch (m_preload) {
3002     case MediaPlayer::None:
3003         return ASCIILiteral("none");
3004     case MediaPlayer::MetaData:
3005         return ASCIILiteral("metadata");
3006     case MediaPlayer::Auto:
3007         return ASCIILiteral("auto");
3008     }
3009
3010     ASSERT_NOT_REACHED();
3011     return String();
3012 }
3013
3014 void HTMLMediaElement::setPreload(const String& preload)
3015 {
3016     LOG(Media, "HTMLMediaElement::setPreload(%p) - %s", this, preload.utf8().data());
3017 #if ENABLE(MEDIA_STREAM)
3018     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3019     // "preload" - On getting: none. On setting: ignored.
3020     if (m_mediaStreamSrcObject)
3021         return;
3022 #endif
3023
3024     setAttribute(preloadAttr, preload);
3025 }
3026
3027 void HTMLMediaElement::play(PlayPromise&& promise)
3028 {
3029     LOG(Media, "HTMLMediaElement::play(%p)", this);
3030
3031     if (!m_mediaSession->playbackPermitted(*this)) {
3032         promise.reject(NotAllowedError);
3033         return;
3034     }
3035
3036     if (m_error && m_error->code() == MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED) {
3037         promise.reject(NOT_SUPPORTED_ERR, "The operation is not supported.");
3038         return;
3039     }
3040
3041     if (ScriptController::processingUserGestureForMedia())
3042         removeBehaviorsRestrictionsAfterFirstUserGesture();
3043
3044     if (!playInternal())
3045         promise.reject(NotAllowedError);
3046
3047     m_pendingPlayPromises.append(WTFMove(promise));
3048 }
3049
3050 void HTMLMediaElement::play()
3051 {
3052     LOG(Media, "HTMLMediaElement::play(%p)", this);
3053
3054     if (!m_mediaSession->playbackPermitted(*this))
3055         return;
3056     if (ScriptController::processingUserGestureForMedia())
3057         removeBehaviorsRestrictionsAfterFirstUserGesture();
3058
3059     playInternal();
3060 }
3061
3062 bool HTMLMediaElement::playInternal()
3063 {
3064     LOG(Media, "HTMLMediaElement::playInternal(%p)", this);
3065     
3066     if (!m_mediaSession->clientWillBeginPlayback()) {
3067         LOG(Media, "  returning because of interruption");
3068         return false;
3069     }
3070
3071     // 4.8.10.9. Playing the media resource
3072     if (!m_player || m_networkState == NETWORK_EMPTY)
3073         scheduleDelayedAction(LoadMediaResource);
3074
3075     if (endedPlayback())
3076         seekInternal(MediaTime::zeroTime());
3077
3078     if (m_mediaController)
3079         m_mediaController->bringElementUpToSpeed(this);
3080
3081     if (m_paused) {
3082         m_paused = false;
3083         invalidateCachedTime();
3084         scheduleEvent(eventNames().playEvent);
3085
3086         if (m_readyState <= HAVE_CURRENT_DATA)
3087             scheduleEvent(eventNames().waitingEvent);
3088         else if (m_readyState >= HAVE_FUTURE_DATA)
3089             scheduleNotifyAboutPlaying();
3090
3091 #if ENABLE(MEDIA_SESSION)
3092         // 6.3 Activating a media session from a media element
3093         // When the play() method is invoked, the paused attribute is true, and the readyState attribute has the value
3094         // HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA, then
3095         // 1. Let media session be the value of the current media session.
3096         // 2. If we are not currently in media session's list of active participating media elements then append
3097         //    ourselves to this list.
3098         // 3. Let activated be the result of running the media session invocation algorithm for media session.
3099         // 4. If activated is failure, pause ourselves.
3100         if (m_readyState == HAVE_ENOUGH_DATA || m_readyState == HAVE_FUTURE_DATA) {
3101             if (m_session) {
3102                 m_session->addActiveMediaElement(*this);
3103
3104                 if (m_session->kind() == MediaSessionKind::Content) {
3105                     if (Page* page = document().page())
3106                         page->chrome().client().focusedContentMediaElementDidChange(m_elementID);
3107                 }
3108
3109                 if (!m_session->invoke()) {
3110                     pause();
3111                     return false;
3112                 }
3113             }
3114         }
3115 #endif
3116     } else if (m_readyState >= HAVE_FUTURE_DATA)
3117         scheduleResolvePendingPlayPromises();
3118
3119     m_autoplaying = false;
3120     updatePlayState();
3121     updateMediaController();
3122     return true;
3123 }
3124
3125 void HTMLMediaElement::pause()
3126 {
3127     LOG(Media, "HTMLMediaElement::pause(%p)", this);
3128
3129     if (!m_mediaSession->playbackPermitted(*this))
3130         return;
3131
3132     pauseInternal();
3133 }
3134
3135
3136 void HTMLMediaElement::pauseInternal()
3137 {
3138     LOG(Media, "HTMLMediaElement::pauseInternal(%p)", this);
3139
3140     if (!m_mediaSession->clientWillPausePlayback()) {
3141         LOG(Media, "  returning because of interruption");
3142         return;
3143     }
3144
3145     // 4.8.10.9. Playing the media resource
3146     if (!m_player || m_networkState == NETWORK_EMPTY) {
3147         // Unless the restriction on media requiring user action has been lifted
3148         // don't trigger loading if a script calls pause().
3149         if (!m_mediaSession->playbackPermitted(*this))
3150             return;
3151         scheduleDelayedAction(LoadMediaResource);
3152     }
3153
3154     m_autoplaying = false;
3155
3156     if (!m_paused) {
3157         m_paused = true;
3158         scheduleTimeupdateEvent(false);
3159         scheduleEvent(eventNames().pauseEvent);
3160         rejectPendingPlayPromises(DOMError::create("AbortError", "The operation was aborted."));
3161
3162         if (MemoryPressureHandler::singleton().isUnderMemoryPressure())
3163             purgeBufferedDataIfPossible();
3164     }
3165
3166     updatePlayState();
3167 }
3168
3169 #if ENABLE(MEDIA_SOURCE)
3170 void HTMLMediaElement::closeMediaSource()
3171 {
3172     if (!m_mediaSource)
3173         return;
3174
3175     m_mediaSource->close();
3176     m_mediaSource = nullptr;
3177 }
3178 #endif
3179
3180 #if ENABLE(ENCRYPTED_MEDIA)
3181 void HTMLMediaElement::webkitGenerateKeyRequest(const String& keySystem, const RefPtr<Uint8Array>& initData, ExceptionCode& ec)
3182 {
3183 #if ENABLE(ENCRYPTED_MEDIA_V2)
3184     static bool firstTime = true;
3185     if (firstTime && scriptExecutionContext()) {
3186         scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("'HTMLMediaElement.webkitGenerateKeyRequest()' is deprecated.  Use 'MediaKeys.createSession()' instead."));
3187         firstTime = false;
3188     }
3189 #endif
3190
3191     if (keySystem.isEmpty()) {
3192         ec = SYNTAX_ERR;
3193         return;
3194     }
3195
3196     if (!m_player) {
3197         ec = INVALID_STATE_ERR;
3198         return;
3199     }
3200
3201     const unsigned char* initDataPointer = nullptr;
3202     unsigned initDataLength = 0;
3203     if (initData) {
3204         initDataPointer = initData->data();
3205         initDataLength = initData->length();
3206     }
3207
3208     MediaPlayer::MediaKeyException result = m_player->generateKeyRequest(keySystem, initDataPointer, initDataLength);
3209     ec = exceptionCodeForMediaKeyException(result);
3210 }
3211
3212 void HTMLMediaElement::webkitAddKey(const String& keySystem, Uint8Array& key, const RefPtr<Uint8Array>& initData, const String& sessionId, ExceptionCode& ec)
3213 {
3214 #if ENABLE(ENCRYPTED_MEDIA_V2)
3215     static bool firstTime = true;
3216     if (firstTime && scriptExecutionContext()) {
3217         scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("'HTMLMediaElement.webkitAddKey()' is deprecated.  Use 'MediaKeySession.update()' instead."));
3218         firstTime = false;
3219     }
3220 #endif
3221
3222     if (keySystem.isEmpty()) {
3223         ec = SYNTAX_ERR;
3224         return;
3225     }
3226
3227     if (!key.length()) {
3228         ec = TYPE_MISMATCH_ERR;
3229         return;
3230     }
3231
3232     if (!m_player) {
3233         ec = INVALID_STATE_ERR;
3234         return;
3235     }
3236
3237     const unsigned char* initDataPointer = nullptr;
3238     unsigned initDataLength = 0;
3239     if (initData) {
3240         initDataPointer = initData->data();
3241         initDataLength = initData->length();
3242     }
3243
3244     MediaPlayer::MediaKeyException result = m_player->addKey(keySystem, key.data(), key.length(), initDataPointer, initDataLength, sessionId);
3245     ec = exceptionCodeForMediaKeyException(result);
3246 }
3247
3248 void HTMLMediaElement::webkitCancelKeyRequest(const String& keySystem, const String& sessionId, ExceptionCode& ec)
3249 {
3250     if (keySystem.isEmpty()) {
3251         ec = SYNTAX_ERR;
3252         return;
3253     }
3254
3255     if (!m_player) {
3256         ec = INVALID_STATE_ERR;
3257         return;
3258     }
3259
3260     MediaPlayer::MediaKeyException result = m_player->cancelKeyRequest(keySystem, sessionId);
3261     ec = exceptionCodeForMediaKeyException(result);
3262 }
3263
3264 #endif
3265
3266 bool HTMLMediaElement::loop() const
3267 {
3268     return fastHasAttribute(loopAttr);
3269 }
3270
3271 void HTMLMediaElement::setLoop(bool b)
3272 {
3273     LOG(Media, "HTMLMediaElement::setLoop(%p) - %s", this, boolString(b));
3274     setBooleanAttribute(loopAttr, b);
3275 }
3276
3277 bool HTMLMediaElement::controls() const
3278 {
3279     Frame* frame = document().frame();
3280
3281     // always show controls when scripting is disabled
3282     if (frame && !frame->script().canExecuteScripts(NotAboutToExecuteScript))
3283         return true;
3284
3285     return fastHasAttribute(controlsAttr);
3286 }
3287
3288 void HTMLMediaElement::setControls(bool b)
3289 {
3290     LOG(Media, "HTMLMediaElement::setControls(%p) - %s", this, boolString(b));
3291     setBooleanAttribute(controlsAttr, b);
3292 }
3293
3294 double HTMLMediaElement::volume() const
3295 {
3296     return m_volume;
3297 }
3298
3299 void HTMLMediaElement::setVolume(double vol, ExceptionCode& ec)
3300 {
3301     LOG(Media, "HTMLMediaElement::setVolume(%p) - %f", this, vol);
3302
3303     if (vol < 0.0f || vol > 1.0f) {
3304         ec = INDEX_SIZE_ERR;
3305         return;
3306     }
3307     
3308 #if !PLATFORM(IOS)
3309     if (m_volume != vol) {
3310         m_volume = vol;
3311         m_volumeInitialized = true;
3312         updateVolume();
3313         scheduleEvent(eventNames().volumechangeEvent);
3314     }
3315 #endif
3316 }
3317
3318 bool HTMLMediaElement::muted() const
3319 {
3320     return m_explicitlyMuted ? m_muted : fastHasAttribute(mutedAttr);
3321 }
3322
3323 void HTMLMediaElement::setMuted(bool muted)
3324 {
3325     LOG(Media, "HTMLMediaElement::setMuted(%p) - %s", this, boolString(muted));
3326
3327 #if PLATFORM(IOS)
3328     UNUSED_PARAM(muted);
3329 #else
3330     if (m_muted != muted || !m_explicitlyMuted) {
3331         m_muted = muted;
3332         m_explicitlyMuted = true;
3333         // Avoid recursion when the player reports volume changes.
3334         if (!processingMediaPlayerCallback()) {
3335             if (m_player) {
3336                 m_player->setMuted(effectiveMuted());
3337                 if (hasMediaControls())
3338                     mediaControls()->changedMute();
3339             }
3340         }
3341         scheduleEvent(eventNames().volumechangeEvent);
3342
3343         updateShouldPlay();
3344
3345 #if ENABLE(MEDIA_SESSION)
3346         document().updateIsPlayingMedia(m_elementID);
3347 #else
3348         document().updateIsPlayingMedia();
3349 #endif
3350
3351 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
3352         updateMediaState(UpdateMediaState::Asynchronously);
3353 #endif
3354     }
3355 #endif
3356
3357     updatePlaybackControlsManager();
3358 }
3359
3360 void HTMLMediaElement::togglePlayState()
3361 {
3362     LOG(Media, "HTMLMediaElement::togglePlayState(%p) - canPlay() is %s", this, boolString(canPlay()));
3363
3364     // We can safely call the internal play/pause methods, which don't check restrictions, because
3365     // this method is only called from the built-in media controller
3366     if (canPlay()) {
3367         updatePlaybackRate();
3368         playInternal();
3369     } else 
3370         pauseInternal();
3371 }
3372
3373 void HTMLMediaElement::beginScrubbing()
3374 {
3375     LOG(Media, "HTMLMediaElement::beginScrubbing(%p) - paused() is %s", this, boolString(paused()));
3376
3377     if (!paused()) {
3378         if (ended()) {
3379             // Because a media element stays in non-paused state when it reaches end, playback resumes 
3380             // when the slider is dragged from the end to another position unless we pause first. Do 
3381             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
3382             pause();
3383         } else {
3384             // Not at the end but we still want to pause playback so the media engine doesn't try to
3385             // continue playing during scrubbing. Pause without generating an event as we will 
3386             // unpause after scrubbing finishes.
3387             setPausedInternal(true);
3388         }
3389     }
3390 }
3391
3392 void HTMLMediaElement::endScrubbing()
3393 {
3394     LOG(Media, "HTMLMediaElement::endScrubbing(%p) - m_pausedInternal is %s", this, boolString(m_pausedInternal));
3395
3396     if (m_pausedInternal)
3397         setPausedInternal(false);
3398 }
3399
3400 void HTMLMediaElement::beginScanning(ScanDirection direction)
3401 {
3402     m_scanType = supportsScanning() ? Scan : Seek;
3403     m_scanDirection = direction;
3404
3405     if (m_scanType == Seek) {
3406         // Scanning by seeking requires the video to be paused during scanning.
3407         m_actionAfterScan = paused() ? Nothing : Play;
3408         pause();
3409     } else {
3410         // Scanning by scanning requires the video to be playing during scanninging.
3411         m_actionAfterScan = paused() ? Pause : Nothing;
3412         play();
3413         setPlaybackRate(nextScanRate());
3414     }
3415
3416     m_scanTimer.start(0, m_scanType == Seek ? SeekRepeatDelay : ScanRepeatDelay);
3417 }
3418
3419 void HTMLMediaElement::endScanning()
3420 {
3421     if (m_scanType == Scan)
3422         setPlaybackRate(defaultPlaybackRate());
3423
3424     if (m_actionAfterScan == Play)
3425         play();
3426     else if (m_actionAfterScan == Pause)
3427         pause();
3428
3429     if (m_scanTimer.isActive())
3430         m_scanTimer.stop();
3431 }
3432
3433 double HTMLMediaElement::nextScanRate()
3434 {
3435     double rate = std::min(ScanMaximumRate, fabs(playbackRate() * 2));
3436     if (m_scanDirection == Backward)
3437         rate *= -1;
3438 #if PLATFORM(IOS)
3439     rate = std::min(std::max(rate, minFastReverseRate()), maxFastForwardRate());
3440 #endif
3441     return rate;
3442 }
3443
3444 void HTMLMediaElement::scanTimerFired()
3445 {
3446     if (m_scanType == Seek) {
3447         double seekTime = m_scanDirection == Forward ? SeekTime : -SeekTime;
3448         setCurrentTime(currentTime() + seekTime);
3449     } else
3450         setPlaybackRate(nextScanRate());
3451 }
3452
3453 // The spec says to fire periodic timeupdate events (those sent while playing) every
3454 // "15 to 250ms", we choose the slowest frequency
3455 static const double maxTimeupdateEventFrequency = 0.25;
3456
3457 void HTMLMediaElement::startPlaybackProgressTimer()
3458 {
3459     if (m_playbackProgressTimer.isActive())
3460         return;
3461
3462     m_previousProgressTime = monotonicallyIncreasingTime();
3463     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
3464 }
3465
3466 void HTMLMediaElement::playbackProgressTimerFired()
3467 {
3468     ASSERT(m_player);
3469
3470     if (m_fragmentEndTime.isValid() && currentMediaTime() >= m_fragmentEndTime && requestedPlaybackRate() > 0) {
3471         m_fragmentEndTime = MediaTime::invalidTime();
3472         if (!m_mediaController && !m_paused) {
3473             // changes paused to true and fires a simple event named pause at the media element.
3474             pauseInternal();
3475         }
3476     }
3477     
3478     scheduleTimeupdateEvent(true);
3479
3480     if (!requestedPlaybackRate())
3481         return;
3482
3483     if (!m_paused && hasMediaControls())
3484         mediaControls()->playbackProgressed();
3485
3486 #if ENABLE(VIDEO_TRACK)
3487     updateActiveTextTrackCues(currentMediaTime());
3488 #endif
3489
3490 #if ENABLE(MEDIA_SOURCE)
3491     if (m_mediaSource)
3492         m_mediaSource->monitorSourceBuffers();
3493 #endif
3494 }
3495
3496 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
3497 {
3498     double now = monotonicallyIncreasingTime();
3499     double timedelta = now - m_clockTimeAtLastUpdateEvent;
3500
3501     // throttle the periodic events
3502     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
3503         return;
3504
3505     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
3506     // event at a given time so filter here
3507     MediaTime movieTime = currentMediaTime();
3508     if (movieTime != m_lastTimeUpdateEventMovieTime) {
3509         scheduleEvent(eventNames().timeupdateEvent);
3510         m_clockTimeAtLastUpdateEvent = now;
3511         m_lastTimeUpdateEventMovieTime = movieTime;
3512     }
3513 }
3514
3515 bool HTMLMediaElement::canPlay() const
3516 {
3517     return paused() || ended() || m_readyState < HAVE_METADATA;
3518 }
3519
3520 double HTMLMediaElement::percentLoaded() const
3521 {
3522     if (!m_player)
3523         return 0;
3524     MediaTime duration = m_player->duration();
3525
3526     if (!duration || duration.isPositiveInfinite() || duration.isNegativeInfinite())
3527         return 0;
3528
3529     MediaTime buffered = MediaTime::zeroTime();
3530     bool ignored;
3531     std::unique_ptr<PlatformTimeRanges> timeRanges = m_player->buffered();
3532     for (unsigned i = 0; i < timeRanges->length(); ++i) {
3533         MediaTime start = timeRanges->start(i, ignored);
3534         MediaTime end = timeRanges->end(i, ignored);
3535         buffered += end - start;
3536     }
3537     return buffered.toDouble() / duration.toDouble();
3538 }
3539
3540 #if ENABLE(VIDEO_TRACK)
3541
3542 void HTMLMediaElement::mediaPlayerDidAddAudioTrack(PassRefPtr<AudioTrackPrivate> prpTrack)
3543 {
3544     if (isPlaying() && !m_mediaSession->playbackPermitted(*this))
3545         pauseInternal();
3546
3547     addAudioTrack(AudioTrack::create(this, prpTrack));
3548 }
3549
3550 void HTMLMediaElement::mediaPlayerDidAddTextTrack(PassRefPtr<InbandTextTrackPrivate> prpTrack)
3551 {
3552     // 4.8.10.12.2 Sourcing in-band text tracks
3553     // 1. Associate the relevant data with a new text track and its corresponding new TextTrack object.
3554     RefPtr<InbandTextTrack> textTrack = InbandTextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, prpTrack);
3555     textTrack->setMediaElement(this);
3556     
3557     // 2. Set the new text track's kind, label, and language based on the semantics of the relevant data,
3558     // as defined by the relevant specification. If there is no label in that data, then the label must
3559     // be set to the empty string.
3560     // 3. Associate the text track list of cues with the rules for updating the text track rendering appropriate
3561     // for the format in question.
3562     // 4. If the new text track's kind is metadata, then set the text track in-band metadata track dispatch type
3563     // as follows, based on the type of the media resource:
3564     // 5. Populate the new text track's list of cues with the cues parsed so far, folllowing the guidelines for exposing
3565     // cues, and begin updating it dynamically as necessary.
3566     //   - Thess are all done by the media engine.
3567     
3568     // 6. Set the new text track's readiness state to loaded.
3569     textTrack->setReadinessState(TextTrack::Loaded);
3570     
3571     // 7. Set the new text track's mode to the mode consistent with the user's preferences and the requirements of
3572     // the relevant specification for the data.
3573     //  - This will happen in configureTextTracks()
3574     scheduleDelayedAction(ConfigureTextTracks);
3575     
3576     // 8. Add the new text track to the media element's list of text tracks.
3577     // 9. Fire an event with the name addtrack, that does not bubble and is not cancelable, and that uses the TrackEvent
3578     // interface, with the track attribute initialized to the text track's TextTrack object, at the media element's
3579     // textTracks attribute's TextTrackList object.
3580     addTextTrack(textTrack.releaseNonNull());
3581 }
3582
3583 void HTMLMediaElement::mediaPlayerDidAddVideoTrack(PassRefPtr<VideoTrackPrivate> prpTrack)
3584 {
3585     addVideoTrack(VideoTrack::create(this, prpTrack));
3586 }
3587
3588 void HTMLMediaElement::mediaPlayerDidRemoveAudioTrack(PassRefPtr<AudioTrackPrivate> prpTrack)
3589 {
3590     prpTrack->willBeRemoved();
3591 }
3592
3593 void HTMLMediaElement::mediaPlayerDidRemoveTextTrack(PassRefPtr<InbandTextTrackPrivate> prpTrack)
3594 {
3595     prpTrack->willBeRemoved();
3596 }
3597
3598 void HTMLMediaElement::mediaPlayerDidRemoveVideoTrack(PassRefPtr<VideoTrackPrivate> prpTrack)
3599 {
3600     prpTrack->willBeRemoved();
3601 }
3602
3603 void HTMLMediaElement::closeCaptionTracksChanged()
3604 {
3605     if (hasMediaControls())
3606         mediaControls()->closedCaptionTracksChanged();
3607 }
3608
3609 void HTMLMediaElement::addAudioTrack(Ref<AudioTrack>&& track)
3610 {
3611     audioTracks().append(WTFMove(track));
3612 }
3613
3614 void HTMLMediaElement::addTextTrack(Ref<TextTrack>&& track)
3615 {
3616     if (!m_requireCaptionPreferencesChangedCallbacks) {
3617         m_requireCaptionPreferencesChangedCallbacks = true;
3618         Document& document = this->document();
3619         document.registerForCaptionPreferencesChangedCallbacks(this);
3620         if (Page* page = document.page())
3621             m_captionDisplayMode = page->group().captionPreferences().captionDisplayMode();
3622     }
3623
3624     textTracks().append(WTFMove(track));
3625
3626     closeCaptionTracksChanged();
3627 }
3628
3629 void HTMLMediaElement::addVideoTrack(Ref<VideoTrack>&& track)
3630 {
3631     videoTracks().append(WTFMove(track));
3632 }
3633
3634 void HTMLMediaElement::removeAudioTrack(AudioTrack& track)
3635 {
3636     m_audioTracks->remove(track);
3637 }
3638
3639 void HTMLMediaElement::removeTextTrack(TextTrack& track, bool scheduleEvent)
3640 {
3641     TrackDisplayUpdateScope scope(this);
3642     if (TextTrackCueList* cues = track.cues())
3643         textTrackRemoveCues(&track, cues);
3644     track.clearClient();
3645     if (m_textTracks)
3646         m_textTracks->remove(track, scheduleEvent);
3647
3648     closeCaptionTracksChanged();
3649 }
3650
3651 void HTMLMediaElement::removeVideoTrack(VideoTrack& track)
3652 {
3653     m_videoTracks->remove(track);
3654 }
3655
3656 void HTMLMediaElement::forgetResourceSpecificTracks()
3657 {
3658     while (m_audioTracks &&  m_audioTracks->length())
3659         removeAudioTrack(*m_audioTracks->lastItem());
3660
3661     if (m_textTracks) {
3662         TrackDisplayUpdateScope scope(this);
3663         for (int i = m_textTracks->length() - 1; i >= 0; --i) {
3664             auto& track = *m_textTracks->item(i);
3665             if (track.trackType() == TextTrack::InBand)
3666                 removeTextTrack(track, false);
3667         }
3668     }
3669
3670     while (m_videoTracks &&  m_videoTracks->length())
3671         removeVideoTrack(*m_videoTracks->lastItem());
3672 }
3673
3674 RefPtr<TextTrack> HTMLMediaElement::addTextTrack(const String& kind, const String& label, const String& language, ExceptionCode& ec)
3675 {
3676     // 4.8.10.12.4 Text track API
3677     // The addTextTrack(kind, label, language) method of media elements, when invoked, must run the following steps:
3678
3679     // 1. If kind is not one of the following strings, then throw a SyntaxError exception and abort these steps
3680     if (!TextTrack::isValidKindKeyword(kind)) {
3681         ec = TypeError;
3682         return nullptr;
3683     }
3684
3685     // 2. If the label argument was omitted, let label be the empty string.
3686     // 3. If the language argument was omitted, let language be the empty string.
3687     // 4. Create a new TextTrack object.
3688
3689     // 5. Create a new text track corresponding to the new object, and set its text track kind to kind, its text 
3690     // track label to label, its text track language to language...
3691     auto textTrack = TextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, kind, emptyString(), label, language);
3692
3693     // Note, due to side effects when changing track parameters, we have to
3694     // first append the track to the text track list.
3695
3696     // 6. Add the new text track to the media element's list of text tracks.
3697     addTextTrack(textTrack.copyRef());
3698
3699     // ... its text track readiness state to the text track loaded state ...
3700     textTrack->setReadinessState(TextTrack::Loaded);
3701
3702     // ... its text track mode to the text track hidden mode, and its text track list of cues to an empty list ...
3703     textTrack->setMode(TextTrack::Mode::Hidden);
3704
3705     return WTFMove(textTrack);
3706 }
3707
3708 AudioTrackList& HTMLMediaElement::audioTracks()
3709 {
3710     if (!m_audioTracks)
3711         m_audioTracks = AudioTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
3712
3713     return *m_audioTracks;
3714 }
3715
3716 TextTrackList& HTMLMediaElement::textTracks()
3717 {
3718     if (!m_textTracks)
3719         m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
3720
3721     return *m_textTracks;
3722 }
3723
3724 VideoTrackList& HTMLMediaElement::videoTracks()
3725 {
3726     if (!m_videoTracks)
3727         m_videoTracks = VideoTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
3728
3729     return *m_videoTracks;
3730 }
3731
3732 void HTMLMediaElement::didAddTextTrack(HTMLTrackElement* trackElement)
3733 {
3734     ASSERT(trackElement->hasTagName(trackTag));
3735
3736     // 4.8.10.12.3 Sourcing out-of-band text tracks
3737     // When a track element's parent element changes and the new parent is a media element, 
3738     // then the user agent must add the track element's corresponding text track to the 
3739     // media element's list of text tracks ... [continues in TextTrackList::append]
3740     RefPtr<TextTrack> textTrack = trackElement->track();
3741     if (!textTrack)
3742         return;
3743     
3744     addTextTrack(textTrack.releaseNonNull());
3745     
3746     // Do not schedule the track loading until parsing finishes so we don't start before all tracks
3747     // in the markup have been added.
3748     if (!m_parsingInProgress)
3749         scheduleDelayedAction(ConfigureTextTracks);
3750
3751     if (hasMediaControls())
3752         mediaControls()->closedCaptionTracksChanged();
3753 }
3754
3755 void HTMLMediaElement::didRemoveTextTrack(HTMLTrackElement* trackElement)
3756 {
3757     ASSERT(trackElement->hasTagName(trackTag));
3758
3759 #if !LOG_DISABLED
3760     if (trackElement->hasTagName(trackTag)) {
3761         URL url = trackElement->getNonEmptyURLAttribute(srcAttr);
3762         LOG(Media, "HTMLMediaElement::didRemoveTrack(%p) - 'src' is %s", this, urlForLoggingMedia(url).utf8().data());
3763     }
3764 #endif
3765
3766     RefPtr<TextTrack> textTrack = trackElement->track();
3767     if (!textTrack)
3768         return;
3769     
3770     textTrack->setHasBeenConfigured(false);
3771
3772     if (!m_textTracks)
3773         return;
3774     
3775     // 4.8.10.12.3 Sourcing out-of-band text tracks
3776     // When a track element's parent element changes and the old parent was a media element, 
3777     // then the user agent must remove the track element's corresponding text track from the 
3778     // media element's list of text tracks.
3779     removeTextTrack(*textTrack);
3780
3781     size_t index = m_textTracksWhenResourceSelectionBegan.find(textTrack.get());
3782     if (index != notFound)
3783         m_textTracksWhenResourceSelectionBegan.remove(index);
3784 }
3785
3786 void HTMLMediaElement::configureTextTrackGroup(const TrackGroup& group)
3787 {
3788     ASSERT(group.tracks.size());
3789
3790     LOG(Media, "HTMLMediaElement::configureTextTrackGroup(%p)", this);
3791
3792     Page* page = document().page();
3793     CaptionUserPreferences* captionPreferences = page ? &page->group().captionPreferences() : 0;
3794     CaptionUserPreferences::CaptionDisplayMode displayMode = captionPreferences ? captionPreferences->captionDisplayMode() : CaptionUserPreferences::Automatic;
3795
3796     // First, find the track in the group that should be enabled (if any).
3797     Vector<RefPtr<TextTrack>> currentlyEnabledTracks;
3798     RefPtr<TextTrack> trackToEnable;
3799     RefPtr<TextTrack> defaultTrack;
3800     RefPtr<TextTrack> fallbackTrack;
3801     RefPtr<TextTrack> forcedSubitleTrack;
3802     int highestTrackScore = 0;
3803     int highestForcedScore = 0;
3804
3805     // If there is a visible track, it has already been configured so it won't be considered in the loop below. We don't want to choose another
3806     // track if it is less suitable, and we do want to disable it if another track is more suitable.
3807     int alreadyVisibleTrackScore = 0;
3808     if (group.visibleTrack && captionPreferences) {
3809         alreadyVisibleTrackScore = captionPreferences->textTrackSelectionScore(group.visibleTrack.get(), this);
3810         currentlyEnabledTracks.append(group.visibleTrack);
3811     }
3812
3813     for (size_t i = 0; i < group.tracks.size(); ++i) {
3814         RefPtr<TextTrack> textTrack = group.tracks[i];
3815
3816         if (m_processingPreferenceChange && textTrack->mode() == TextTrack::Mode::Showing)
3817             currentlyEnabledTracks.append(textTrack);
3818
3819         int trackScore = captionPreferences ? captionPreferences->textTrackSelectionScore(textTrack.get(), this) : 0;
3820         LOG(Media, "HTMLMediaElement::configureTextTrackGroup(%p) -  '%s' track with language '%s' has score %i", this, textTrack->kindKeyword().string().utf8().data(), textTrack->language().string().utf8().data(), trackScore);
3821
3822         if (trackScore) {
3823
3824             // * If the text track kind is { [subtitles or captions] [descriptions] } and the user has indicated an interest in having a
3825             // track with this text track kind, text track language, and text track label enabled, and there is no
3826             // other text track in the media element's list of text tracks with a text track kind of either subtitles
3827             // or captions whose text track mode is showing
3828             // ...
3829             // * If the text track kind is chapters and the text track language is one that the user agent has reason
3830             // to believe is appropriate for the user, and there is no other text track in the media element's list of
3831             // text tracks with a text track kind of chapters whose text track mode is showing
3832             //    Let the text track mode be showing.
3833             if (trackScore > highestTrackScore && trackScore > alreadyVisibleTrackScore) {
3834                 highestTrackScore = trackScore;
3835                 trackToEnable = textTrack;
3836             }
3837
3838             if (!defaultTrack && textTrack->isDefault())
3839                 defaultTrack = textTrack;
3840             if (!defaultTrack && !fallbackTrack)
3841                 fallbackTrack = textTrack;
3842             if (textTrack->containsOnlyForcedSubtitles() && trackScore > highestForcedScore) {
3843                 forcedSubitleTrack = textTrack;
3844                 highestForcedScore = trackScore;
3845             }
3846         } else if (!group.visibleTrack && !defaultTrack && textTrack->isDefault()) {
3847             // * If the track element has a default attribute specified, and there is no other text track in the media
3848             // element's list of text tracks whose text track mode is showing or showing by default
3849             //    Let the text track mode be showing by default.
3850             if (group.kind != TrackGroup::CaptionsAndSubtitles || displayMode != CaptionUserPreferences::ForcedOnly)
3851                 defaultTrack = textTrack;
3852         }
3853     }
3854
3855     if (displayMode != CaptionUserPreferences::Manual) {
3856         if (!trackToEnable && defaultTrack)
3857             trackToEnable = defaultTrack;
3858
3859         // If no track matches the user's preferred language, none was marked as 'default', and there is a forced subtitle track
3860         // in the same language as the language of the primary audio track, enable it.
3861         if (!trackToEnable && forcedSubitleTrack)
3862             trackToEnable = forcedSubitleTrack;
3863
3864         // If no track matches, don't disable an already visible track unless preferences say they all should be off.
3865         if (group.kind != TrackGroup::CaptionsAndSubtitles || displayMode != CaptionUserPreferences::ForcedOnly) {
3866             if (!trackToEnable && !defaultTrack && group.visibleTrack)
3867                 trackToEnable = group.visibleTrack;
3868         }
3869
3870         // If no track matches the user's preferred language and non was marked 'default', enable the first track
3871         // because the user has explicitly stated a preference for this kind of track.
3872         if (!trackToEnable && fallbackTrack)
3873             trackToEnable = fallbackTrack;
3874
3875         if (trackToEnable)
3876             m_subtitleTrackLanguage = trackToEnable->language();
3877         else
3878             m_subtitleTrackLanguage = emptyString();
3879     }
3880
3881     if (currentlyEnabledTracks.size()) {
3882         for (size_t i = 0; i < currentlyEnabledTracks.size(); ++i) {
3883             RefPtr<TextTrack> textTrack = currentlyEnabledTracks[i];
3884             if (textTrack != trackToEnable)
3885                 textTrack->setMode(TextTrack::Mode::Disabled);
3886         }
3887     }
3888
3889     if (trackToEnable) {
3890         trackToEnable->setMode(TextTrack::Mode::Showing);
3891
3892         // If user preferences indicate we should always display captions, make sure we reflect the
3893         // proper status via the webkitClosedCaptionsVisible API call:
3894         if (!webkitClosedCaptionsVisible() && closedCaptionsVisible() && displayMode == CaptionUserPreferences::AlwaysOn)
3895             m_webkitLegacyClosedCaptionOverride = true;
3896     }
3897
3898     m_processingPreferenceChange = false;
3899 }
3900
3901 static JSC::JSValue controllerJSValue(JSC::ExecState& exec, JSDOMGlobalObject& globalObject, HTMLMediaElement& media)
3902 {
3903     auto mediaJSWrapper = toJS(&exec, &globalObject, media);
3904     
3905     // Retrieve the controller through the JS object graph
3906     JSC::JSObject* mediaJSWrapperObject = JSC::jsDynamicCast<JSC::JSObject*>(mediaJSWrapper);
3907     if (!mediaJSWrapperObject)
3908         return JSC::jsNull();
3909     
3910     JSC::Identifier controlsHost = JSC::Identifier::fromString(&exec.vm(), "controlsHost");
3911     JSC::JSValue controlsHostJSWrapper = mediaJSWrapperObject->get(&exec, controlsHost);
3912     if (exec.hadException())
3913         return JSC::jsNull();
3914
3915     JSC::JSObject* controlsHostJSWrapperObject = JSC::jsDynamicCast<JSC::JSObject*>(controlsHostJSWrapper);
3916     if (!controlsHostJSWrapperObject)
3917         return JSC::jsNull();
3918
3919     JSC::Identifier controllerID = JSC::Identifier::fromString(&exec.vm(), "controller");
3920     JSC::JSValue controllerJSWrapper = controlsHostJSWrapperObject->get(&exec, controllerID);
3921     if (exec.hadException())
3922         return JSC::jsNull();
3923
3924     return controllerJSWrapper;
3925 }
3926
3927 void HTMLMediaElement::ensureMediaControlsShadowRoot()
3928 {
3929     ASSERT(!m_creatingControls);
3930     m_creatingControls = true;
3931     ensureUserAgentShadowRoot();
3932     m_creatingControls = false;
3933 }
3934
3935 void HTMLMediaElement::updateCaptionContainer()
3936 {
3937     LOG(Media, "HTMLMediaElement::updateCaptionContainer(%p)", this);
3938 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
3939     if (m_haveSetUpCaptionContainer)
3940         return;
3941
3942     Page* page = document().page();
3943     if (!page)
3944         return;
3945
3946     DOMWrapperWorld& world = ensureIsolatedWorld();
3947
3948     if (!ensureMediaControlsInjectedScript())
3949         return;
3950
3951     ensureMediaControlsShadowRoot();
3952
3953     if (!m_mediaControlsHost)
3954         m_mediaControlsHost = MediaControlsHost::create(this);
3955
3956     ScriptController& scriptController = document().frame()->script();
3957     JSDOMGlobalObject* globalObject = JSC::jsCast<JSDOMGlobalObject*>(scriptController.globalObject(world));
3958     JSC::ExecState* exec = globalObject->globalExec();
3959     JSC::JSLockHolder lock(exec);
3960
3961     JSC::JSValue controllerValue = controllerJSValue(*exec, *globalObject, *this);
3962     JSC::JSObject* controllerObject = JSC::jsDynamicCast<JSC::JSObject*>(controllerValue);
3963     if (!controllerObject)
3964         return;
3965
3966     // The media controls script must provide a method on the Controller object with the following details.
3967     // Name: updateCaptionContainer
3968     // Parameters:
3969     //     None
3970     // Return value:
3971     //     None
3972     JSC::JSValue methodValue = controllerObject->get(exec, JSC::Identifier::fromString(exec, "updateCaptionContainer"));
3973     JSC::JSObject* methodObject = JSC::jsDynamicCast<JSC::JSObject*>(methodValue);
3974     if (!methodObject)
3975         return;
3976
3977     JSC::CallData callData;
3978     JSC::CallType callType = methodObject->methodTable()->getCallData(methodObject, callData);
3979     if (callType == JSC::CallType::None)
3980         return;
3981
3982     JSC::MarkedArgumentBuffer noArguments;
3983     JSC::call(exec, methodObject, callType, callData, controllerObject, noArguments);
3984     exec->clearException();
3985
3986     m_haveSetUpCaptionContainer = true;
3987 #endif
3988 }
3989
3990 void HTMLMediaElement::layoutSizeChanged()
3991 {
3992 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
3993     RefPtr<HTMLMediaElement> strongThis = this;
3994     std::function<void()> task = [strongThis] {
3995         if (ShadowRoot* root = strongThis->userAgentShadowRoot())
3996             root->dispatchEvent(Event::create("resize", false, false));
3997     };
3998     m_resizeTaskQueue.enqueueTask(task);
3999 #endif
4000 }
4001
4002 void HTMLMediaElement::visibilityDidChange()
4003 {
4004     updateShouldAutoplay();
4005 }
4006
4007 void HTMLMediaElement::setSelectedTextTrack(TextTrack* trackToSelect)
4008 {
4009     TextTrackList& trackList = textTracks();
4010     if (!trackList.length())
4011         return;
4012
4013     if (trackToSelect != TextTrack::captionMenuOffItem() && trackToSelect != TextTrack::captionMenuAutomaticItem()) {
4014         if (!trackToSelect || !trackList.contains(*trackToSelect))
4015             return;
4016         
4017         for (int i = 0, length = trackList.length(); i < length; ++i) {
4018             auto& track = *trackList.item(i);
4019             if (&track != trackToSelect)
4020                 track.setMode(TextTrack::Mode::Disabled);
4021             else
4022                 track.setMode(TextTrack::Mode::Showing);
4023         }
4024     } else if (trackToSelect == TextTrack::captionMenuOffItem()) {
4025         for (int i = 0, length = trackList.length(); i < length; ++i)
4026             trackList.item(i)->setMode(TextTrack::Mode::Disabled);
4027     }
4028
4029     if (!document().page())
4030         return;
4031
4032     auto& captionPreferences = document().page()->group().captionPreferences();
4033     CaptionUserPreferences::CaptionDisplayMode displayMode;
4034     if (trackToSelect == TextTrack::captionMenuOffItem())
4035         displayMode = CaptionUserPreferences::ForcedOnly;
4036     else if (trackToSelect == TextTrack::captionMenuAutomaticItem())
4037         displayMode = CaptionUserPreferences::Automatic;
4038     else {
4039         displayMode = CaptionUserPreferences::AlwaysOn;
4040         if (trackToSelect->language().length())
4041             captionPreferences.setPreferredLanguage(trackToSelect->language());
4042     }
4043
4044     captionPreferences.setCaptionDisplayMode(displayMode);
4045 }
4046
4047 void HTMLMediaElement::configureTextTracks()
4048 {
4049     TrackGroup captionAndSubtitleTracks(TrackGroup::CaptionsAndSubtitles);
4050     TrackGroup descriptionTracks(TrackGroup::Description);
4051     TrackGroup chapterTracks(TrackGroup::Chapter);
4052     TrackGroup metadataTracks(TrackGroup::Metadata);
4053     TrackGroup otherTracks(TrackGroup::Other);
4054
4055     if (!m_textTracks)
4056         return;
4057
4058     for (size_t i = 0; i < m_textTracks->length(); ++i) {
4059         RefPtr<TextTrack> textTrack = m_textTracks->item(i);
4060         if (!textTrack)
4061             continue;
4062
4063         auto kind = textTrack->kind();
4064         TrackGroup* currentGroup;
4065         if (kind == TextTrack::Kind::Subtitles || kind == TextTrack::Kind::Captions || kind == TextTrack::Kind::Forced)
4066             currentGroup = &captionAndSubtitleTracks;
4067         else if (kind == TextTrack::Kind::Descriptions)
4068             currentGroup = &descriptionTracks;
4069         else if (kind == TextTrack::Kind::Chapters)
4070             currentGroup = &chapterTracks;
4071         else if (kind == TextTrack::Kind::Metadata)
4072             currentGroup = &metadataTracks;
4073         else
4074             currentGroup = &otherTracks;
4075
4076         if (!currentGroup->visibleTrack && textTrack->mode() == TextTrack::Mode::Showing)
4077             currentGroup->visibleTrack = textTrack;
4078         if (!currentGroup->defaultTrack && textTrack->isDefault())
4079             currentGroup->defaultTrack = textTrack;
4080
4081         // Do not add this track to the group if it has already been automatically configured
4082         // as we only want to call configureTextTrack once per track so that adding another 
4083         // track after the initial configuration doesn't reconfigure every track - only those 
4084         // that should be changed by the new addition. For example all metadata tracks are 
4085         // disabled by default, and we don't want a track that has been enabled by script 
4086         // to be disabled automatically when a new metadata track is added later.
4087         if (textTrack->hasBeenConfigured())
4088             continue;
4089         
4090         if (textTrack->language().length())
4091             currentGroup->hasSrcLang = true;
4092         currentGroup->tracks.append(textTrack);
4093     }
4094     
4095     if (captionAndSubtitleTracks.tracks.size())
4096         configureTextTrackGroup(captionAndSubtitleTracks);
4097     if (descriptionTracks.tracks.size())
4098         configureTextTrackGroup(descriptionTracks);
4099     if (chapterTracks.tracks.size())
4100         configureTextTrackGroup(chapterTracks);
4101     if (metadataTracks.tracks.size())
4102         configureTextTrackGroup(metadataTracks);
4103     if (otherTracks.tracks.size())
4104         configureTextTrackGroup(otherTracks);
4105
4106     u