Return a Promise from HTMLMediaElement.play()
[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     if (!settings || settings->videoPlaybackRequiresUserGesture()) {
446         // Allow autoplay in a MediaDocument that is not in an iframe.
447         if (document.ownerElement() || !document.isMediaDocument()) {
448             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForVideoRateChange);
449             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForLoad);
450         }
451 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
452         m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureToShowPlaybackTargetPicker);
453 #endif
454     }
455 #if PLATFORM(IOS)
456     else {
457         // Relax RequireUserGestureForFullscreen when videoPlaybackRequiresUserGesture is not set:
458         m_mediaSession->removeBehaviorRestriction(MediaElementSession::RequireUserGestureForFullscreen);
459     }
460 #endif
461
462     if (settings && settings->invisibleAutoplayNotPermitted())
463         m_mediaSession->addBehaviorRestriction(MediaElementSession::InvisibleAutoplayNotPermitted);
464
465     if (document.ownerElement() || !document.isMediaDocument()) {
466         if (settings && settings->audioPlaybackRequiresUserGesture())
467             m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForAudioRateChange);
468
469         if (!settings || !settings->mediaDataLoadsAutomatically())
470             m_mediaSession->addBehaviorRestriction(MediaElementSession::AutoPreloadingNotPermitted);
471
472         if (settings && settings->mainContentUserGestureOverrideEnabled())
473             m_mediaSession->addBehaviorRestriction(MediaElementSession::OverrideUserGestureRequirementForMainContent);
474     }
475
476 #if ENABLE(VIDEO_TRACK)
477     if (document.page())
478         m_captionDisplayMode = document.page()->group().captionPreferences().captionDisplayMode();
479 #endif
480
481 #if ENABLE(MEDIA_SESSION)
482     m_elementID = nextElementID();
483     elementIDsToElements().add(m_elementID, this);
484
485     setSessionInternal(document.defaultMediaSession());
486 #endif
487
488     registerWithDocument(document);
489 }
490
491 HTMLMediaElement::~HTMLMediaElement()
492 {
493     LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this);
494
495     allMediaElements().remove(this);
496
497     m_asyncEventQueue.close();
498
499     setShouldDelayLoadEvent(false);
500     unregisterWithDocument(document());
501
502     if (document().page())
503         document().page()->chrome().client().clearPlaybackControlsManager(*this);
504
505 #if ENABLE(VIDEO_TRACK)
506     if (m_audioTracks) {
507         m_audioTracks->clearElement();
508         for (unsigned i = 0; i < m_audioTracks->length(); ++i)
509             m_audioTracks->item(i)->clearClient();
510     }
511     if (m_textTracks)
512         m_textTracks->clearElement();
513     if (m_textTracks) {
514         for (unsigned i = 0; i < m_textTracks->length(); ++i)
515             m_textTracks->item(i)->clearClient();
516     }
517     if (m_videoTracks) {
518         m_videoTracks->clearElement();
519         for (unsigned i = 0; i < m_videoTracks->length(); ++i)
520             m_videoTracks->item(i)->clearClient();
521     }
522 #endif
523
524 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
525     if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent)) {
526         m_hasPlaybackTargetAvailabilityListeners = false;
527         m_mediaSession->setHasPlaybackTargetAvailabilityListeners(*this, false);
528         updateMediaState();
529     }
530 #endif
531
532     if (m_mediaController) {
533         m_mediaController->removeMediaElement(this);
534         m_mediaController = nullptr;
535     }
536
537 #if ENABLE(MEDIA_SOURCE)
538     closeMediaSource();
539 #endif
540
541 #if ENABLE(ENCRYPTED_MEDIA_V2)
542     setMediaKeys(0);
543 #endif
544
545 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
546     if (m_isolatedWorld)
547         m_isolatedWorld->clearWrappers();
548 #endif
549
550 #if ENABLE(MEDIA_SESSION)
551     if (m_session) {
552         m_session->removeMediaElement(*this);
553         m_session = nullptr;
554     }
555
556     elementIDsToElements().remove(m_elementID);
557 #endif
558
559     m_seekTaskQueue.close();
560     m_promiseTaskQueue.close();
561     m_pauseAfterDetachedTaskQueue.close();
562
563     m_completelyLoaded = true;
564 }
565
566 void HTMLMediaElement::registerWithDocument(Document& document)
567 {
568     m_mediaSession->registerWithDocument(document);
569
570     if (m_isWaitingUntilMediaCanStart)
571         document.addMediaCanStartListener(this);
572
573 #if !PLATFORM(IOS)
574     document.registerForMediaVolumeCallbacks(this);
575     document.registerForPrivateBrowsingStateChangedCallbacks(this);
576 #endif
577
578     document.registerForVisibilityStateChangedCallbacks(this);
579
580 #if ENABLE(VIDEO_TRACK)
581     if (m_requireCaptionPreferencesChangedCallbacks)
582         document.registerForCaptionPreferencesChangedCallbacks(this);
583 #endif
584
585 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
586     if (m_mediaControlsDependOnPageScaleFactor)
587         document.registerForPageScaleFactorChangedCallbacks(this);
588 #endif
589
590 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
591     document.registerForDocumentSuspensionCallbacks(this);
592 #endif
593
594     document.registerForAllowsMediaDocumentInlinePlaybackChangedCallbacks(*this);
595
596     document.addAudioProducer(this);
597     addElementToDocumentMap(*this, document);
598 }
599
600 void HTMLMediaElement::unregisterWithDocument(Document& document)
601 {
602     m_mediaSession->unregisterWithDocument(document);
603
604     if (m_isWaitingUntilMediaCanStart)
605         document.removeMediaCanStartListener(this);
606
607 #if !PLATFORM(IOS)
608     document.unregisterForMediaVolumeCallbacks(this);
609     document.unregisterForPrivateBrowsingStateChangedCallbacks(this);
610 #endif
611
612     document.unregisterForVisibilityStateChangedCallbacks(this);
613
614 #if ENABLE(VIDEO_TRACK)
615     if (m_requireCaptionPreferencesChangedCallbacks)
616         document.unregisterForCaptionPreferencesChangedCallbacks(this);
617 #endif
618
619 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
620     if (m_mediaControlsDependOnPageScaleFactor)
621         document.unregisterForPageScaleFactorChangedCallbacks(this);
622 #endif
623
624 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
625     document.unregisterForDocumentSuspensionCallbacks(this);
626 #endif
627
628     document.unregisterForAllowsMediaDocumentInlinePlaybackChangedCallbacks(*this);
629
630     document.removeAudioProducer(this);
631     removeElementFromDocumentMap(*this, document);
632 }
633
634 void HTMLMediaElement::didMoveToNewDocument(Document* oldDocument)
635 {
636     if (m_shouldDelayLoadEvent) {
637         if (oldDocument)
638             oldDocument->decrementLoadEventDelayCount();
639         document().incrementLoadEventDelayCount();
640     }
641
642     if (oldDocument)
643         unregisterWithDocument(*oldDocument);
644
645     registerWithDocument(document());
646
647     HTMLElement::didMoveToNewDocument(oldDocument);
648     updateShouldAutoplay();
649 }
650
651 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
652 void HTMLMediaElement::prepareForDocumentSuspension()
653 {
654     m_mediaSession->unregisterWithDocument(document());
655 }
656
657 void HTMLMediaElement::resumeFromDocumentSuspension()
658 {
659     m_mediaSession->registerWithDocument(document());
660     updateShouldAutoplay();
661 }
662 #endif
663
664 bool HTMLMediaElement::supportsFocus() const
665 {
666     if (document().isMediaDocument())
667         return false;
668
669     // If no controls specified, we should still be able to focus the element if it has tabIndex.
670     return controls() ||  HTMLElement::supportsFocus();
671 }
672
673 bool HTMLMediaElement::isMouseFocusable() const
674 {
675     return false;
676 }
677
678 void HTMLMediaElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
679 {
680     if (name == srcAttr) {
681 #if PLATFORM(IOS)
682         // Note, unless the restriction on requiring user action has been removed,
683         // do not begin downloading data on iOS.
684         if (!value.isNull() && m_mediaSession->dataLoadingPermitted(*this))
685 #else
686         // Trigger a reload, as long as the 'src' attribute is present.
687         if (!value.isNull())
688 #endif
689         {
690             clearMediaPlayer(LoadMediaResource);
691             scheduleDelayedAction(LoadMediaResource);
692         }
693     } else if (name == controlsAttr)
694         configureMediaControls();
695     else if (name == loopAttr)
696         updateSleepDisabling();
697     else if (name == preloadAttr) {
698         if (equalLettersIgnoringASCIICase(value, "none"))
699             m_preload = MediaPlayer::None;
700         else if (equalLettersIgnoringASCIICase(value, "metadata"))
701             m_preload = MediaPlayer::MetaData;
702         else {
703             // The spec does not define an "invalid value default" but "auto" is suggested as the
704             // "missing value default", so use it for everything except "none" and "metadata"
705             m_preload = MediaPlayer::Auto;
706         }
707
708         // The attribute must be ignored if the autoplay attribute is present
709         if (!autoplay() && m_player)
710             m_player->setPreload(m_mediaSession->effectivePreloadForElement(*this));
711
712     } else if (name == mediagroupAttr)
713         setMediaGroup(value);
714     else
715         HTMLElement::parseAttribute(name, value);
716 }
717
718 void HTMLMediaElement::finishParsingChildren()
719 {
720     HTMLElement::finishParsingChildren();
721     m_parsingInProgress = false;
722     
723 #if ENABLE(VIDEO_TRACK)
724     if (descendantsOfType<HTMLTrackElement>(*this).first())
725         scheduleDelayedAction(ConfigureTextTracks);
726 #endif
727 }
728
729 bool HTMLMediaElement::rendererIsNeeded(const RenderStyle& style)
730 {
731     return controls() && HTMLElement::rendererIsNeeded(style);
732 }
733
734 RenderPtr<RenderElement> HTMLMediaElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
735 {
736     return createRenderer<RenderMedia>(*this, WTFMove(style));
737 }
738
739 bool HTMLMediaElement::childShouldCreateRenderer(const Node& child) const
740 {
741 #if ENABLE(MEDIA_CONTROLS_SCRIPT)
742     return hasShadowRootParent(child) && HTMLElement::childShouldCreateRenderer(child);
743 #else
744     if (!hasMediaControls())
745         return false;
746     // <media> doesn't allow its content, including shadow subtree, to
747     // be rendered. So this should return false for most of the children.
748     // One exception is a shadow tree built for rendering controls which should be visible.
749     // So we let them go here by comparing its subtree root with one of the controls.
750     return &mediaControls()->treeScope() == &child.treeScope()
751         && hasShadowRootParent(child)
752         && HTMLElement::childShouldCreateRenderer(child);
753 #endif
754 }
755
756 Node::InsertionNotificationRequest HTMLMediaElement::insertedInto(ContainerNode& insertionPoint)
757 {
758     LOG(Media, "HTMLMediaElement::insertedInto(%p)", this);
759
760     HTMLElement::insertedInto(insertionPoint);
761     if (insertionPoint.inDocument()) {
762         m_inActiveDocument = true;
763
764 #if PLATFORM(IOS)
765         if (m_networkState == NETWORK_EMPTY && !fastGetAttribute(srcAttr).isEmpty() && m_mediaSession->dataLoadingPermitted(*this))
766 #else
767         if (m_networkState == NETWORK_EMPTY && !fastGetAttribute(srcAttr).isEmpty())
768 #endif
769             scheduleDelayedAction(LoadMediaResource);
770     }
771
772     if (!m_explicitlyMuted) {
773         m_explicitlyMuted = true;
774         m_muted = fastHasAttribute(mutedAttr);
775     }
776
777     configureMediaControls();
778     return InsertionDone;
779 }
780
781 void HTMLMediaElement::pauseAfterDetachedTask()
782 {
783     // If we were re-inserted into an active document, no need to pause.
784     if (m_inActiveDocument)
785         return;
786
787     if (hasMediaControls())
788         mediaControls()->hide();
789     if (m_networkState > NETWORK_EMPTY)
790         pause();
791     if (m_videoFullscreenMode != VideoFullscreenModeNone)
792         exitFullscreen();
793
794     if (!m_player)
795         return;
796
797     size_t extraMemoryCost = m_player->extraMemoryCost();
798     if (extraMemoryCost > m_reportedExtraMemoryCost) {
799         JSC::VM& vm = JSDOMWindowBase::commonVM();
800         JSC::JSLockHolder lock(vm);
801
802         size_t extraMemoryCostDelta = extraMemoryCost - m_reportedExtraMemoryCost;
803         m_reportedExtraMemoryCost = extraMemoryCost;
804         // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated.
805         // https://bugs.webkit.org/show_bug.cgi?id=142595
806         vm.heap.deprecatedReportExtraMemory(extraMemoryCostDelta);
807     }
808 }
809
810 void HTMLMediaElement::removedFrom(ContainerNode& insertionPoint)
811 {
812     LOG(Media, "HTMLMediaElement::removedFrom(%p)", this);
813
814     m_inActiveDocument = false;
815     if (insertionPoint.inDocument()) {
816         // Pause asynchronously to let the operation that removed us finish, in case we get inserted back into a document.
817         m_pauseAfterDetachedTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::pauseAfterDetachedTask, this));
818     }
819
820     HTMLElement::removedFrom(insertionPoint);
821 }
822
823 void HTMLMediaElement::willAttachRenderers()
824 {
825     ASSERT(!renderer());
826 }
827
828 void HTMLMediaElement::didAttachRenderers()
829 {
830     if (RenderElement* renderer = this->renderer()) {
831         renderer->updateFromElement();
832         if (m_mediaSession->hasBehaviorRestriction(MediaElementSession::InvisibleAutoplayNotPermitted)
833             || m_mediaSession->hasBehaviorRestriction(MediaElementSession::OverrideUserGestureRequirementForMainContent))
834             renderer->registerForVisibleInViewportCallback();
835     }
836     updateShouldAutoplay();
837 }
838
839 void HTMLMediaElement::willDetachRenderers()
840 {
841     if (renderer())
842         renderer()->unregisterForVisibleInViewportCallback();
843 }
844
845 void HTMLMediaElement::didDetachRenderers()
846 {
847     updateShouldAutoplay();
848 }
849
850 void HTMLMediaElement::didRecalcStyle(Style::Change)
851 {
852     if (renderer())
853         renderer()->updateFromElement();
854 }
855
856 void HTMLMediaElement::scheduleDelayedAction(DelayedActionType actionType)
857 {
858     LOG(Media, "HTMLMediaElement::scheduleDelayedAction(%p) - setting %s flag", this, actionName(actionType).utf8().data());
859
860     if ((actionType & LoadMediaResource) && !(m_pendingActionFlags & LoadMediaResource)) {
861         prepareForLoad();
862         setFlags(m_pendingActionFlags, LoadMediaResource);
863     }
864
865 #if ENABLE(VIDEO_TRACK)
866     if (actionType & ConfigureTextTracks)
867         setFlags(m_pendingActionFlags, ConfigureTextTracks);
868 #endif
869
870 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
871     if (actionType & CheckPlaybackTargetCompatablity)
872         setFlags(m_pendingActionFlags, CheckPlaybackTargetCompatablity);
873 #endif
874
875     if (actionType & CheckMediaState)
876         setFlags(m_pendingActionFlags, CheckMediaState);
877
878     if (actionType & MediaEngineUpdated)
879         setFlags(m_pendingActionFlags, MediaEngineUpdated);
880
881     m_pendingActionTimer.startOneShot(0);
882 }
883
884 void HTMLMediaElement::scheduleNextSourceChild()
885 {
886     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
887     LOG(Media, "HTMLMediaElement::scheduleNextSourceChild(%p) - setting %s flag", this, actionName(LoadMediaResource).utf8().data());
888     setFlags(m_pendingActionFlags, LoadMediaResource);
889     m_pendingActionTimer.startOneShot(0);
890 }
891
892 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
893 {
894 #if LOG_MEDIA_EVENTS
895     LOG(Media, "HTMLMediaElement::scheduleEvent(%p) - scheduling '%s'", this, eventName.string().ascii().data());
896 #endif
897     RefPtr<Event> event = Event::create(eventName, false, true);
898     
899     // Don't set the event target, the event queue will set it in GenericEventQueue::timerFired and setting it here
900     // will trigger an ASSERT if this element has been marked for deletion.
901
902     m_asyncEventQueue.enqueueEvent(WTFMove(event));
903 }
904
905 void HTMLMediaElement::scheduleResolvePendingPlayPromises()
906 {
907     m_promiseTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::resolvePendingPlayPromises, this));
908 }
909
910 void HTMLMediaElement::rejectPendingPlayPromises(DOMError& error)
911 {
912     Vector<PlayPromise> pendingPlayPromises = WTFMove(m_pendingPlayPromises);
913
914     for (auto& promise : pendingPlayPromises)
915         promise.reject(error);
916 }
917
918 void HTMLMediaElement::resolvePendingPlayPromises()
919 {
920     Vector<PlayPromise> pendingPlayPromises = WTFMove(m_pendingPlayPromises);
921
922     for (auto& promise : pendingPlayPromises)
923         promise.resolve(nullptr);
924 }
925
926 void HTMLMediaElement::scheduleNotifyAboutPlaying()
927 {
928     m_promiseTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::notifyAboutPlaying, this));
929 }
930
931 void HTMLMediaElement::notifyAboutPlaying()
932 {
933     dispatchEvent(Event::create(eventNames().playingEvent, false, true));
934     resolvePendingPlayPromises();
935 }
936
937 void HTMLMediaElement::pendingActionTimerFired()
938 {
939     Ref<HTMLMediaElement> protect(*this); // loadNextSourceChild may fire 'beforeload', which can make arbitrary DOM mutations.
940     PendingActionFlags pendingActions = m_pendingActionFlags;
941     m_pendingActionFlags = 0;
942
943 #if ENABLE(VIDEO_TRACK)
944     if (pendingActions & ConfigureTextTracks)
945         configureTextTracks();
946 #endif
947
948     if (pendingActions & LoadMediaResource) {
949         if (m_loadState == LoadingFromSourceElement)
950             loadNextSourceChild();
951         else
952             loadInternal();
953     }
954
955 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
956     if (pendingActions & CheckPlaybackTargetCompatablity && m_isPlayingToWirelessTarget && !m_player->canPlayToWirelessPlaybackTarget()) {
957         LOG(Media, "HTMLMediaElement::pendingActionTimerFired(%p) - calling setShouldPlayToPlaybackTarget(false)", this);
958         m_failedToPlayToWirelessTarget = true;
959         m_player->setShouldPlayToPlaybackTarget(false);
960     }
961
962     if (pendingActions & CheckMediaState)
963         updateMediaState();
964 #endif
965
966     if (pendingActions & MediaEngineUpdated)
967         mediaEngineWasUpdated();
968 }
969
970 PassRefPtr<MediaError> HTMLMediaElement::error() const 
971 {
972     return m_error;
973 }
974
975 void HTMLMediaElement::setSrc(const String& url)
976 {
977     setAttribute(srcAttr, url);
978 }
979
980 #if ENABLE(MEDIA_STREAM)
981 void HTMLMediaElement::setSrcObject(ScriptExecutionContext& context, MediaStream* mediaStream)
982 {
983     // FIXME: Setting the srcObject attribute may cause other changes to the media element's internal state:
984     // Specifically, if srcObject is specified, the UA must use it as the source of media, even if the src
985     // attribute is also set or children are present. If the value of srcObject is replaced or set to null
986     // the UA must re-run the media element load algorithm.
987     //
988     // https://bugs.webkit.org/show_bug.cgi?id=124896
989
990     m_mediaStreamSrcObject = mediaStream;
991     setSrc(DOMURL::createPublicURL(context, mediaStream));
992 }
993 #endif
994
995 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
996 {
997     return m_networkState;
998 }
999
1000 String HTMLMediaElement::canPlayType(const String& mimeType, const String& keySystem, const URL& url) const
1001 {
1002     MediaEngineSupportParameters parameters;
1003     ContentType contentType(mimeType);
1004     parameters.type = contentType.type().convertToASCIILowercase();
1005     parameters.codecs = contentType.parameter(ASCIILiteral("codecs"));
1006     parameters.url = url;
1007 #if ENABLE(ENCRYPTED_MEDIA)
1008     parameters.keySystem = keySystem;
1009 #else
1010     UNUSED_PARAM(keySystem);
1011 #endif
1012     MediaPlayer::SupportsType support = MediaPlayer::supportsType(parameters, this);
1013     String canPlay;
1014
1015     // 4.8.10.3
1016     switch (support)
1017     {
1018         case MediaPlayer::IsNotSupported:
1019             canPlay = emptyString();
1020             break;
1021         case MediaPlayer::MayBeSupported:
1022             canPlay = ASCIILiteral("maybe");
1023             break;
1024         case MediaPlayer::IsSupported:
1025             canPlay = ASCIILiteral("probably");
1026             break;
1027     }
1028     
1029     LOG(Media, "HTMLMediaElement::canPlayType(%p) - [%s, %s, %s] -> %s", this, mimeType.utf8().data(), keySystem.utf8().data(), url.stringCenterEllipsizedToLength().utf8().data(), canPlay.utf8().data());
1030
1031     return canPlay;
1032 }
1033
1034 double HTMLMediaElement::getStartDate() const
1035 {
1036     return m_player->getStartDate().toDouble();
1037 }
1038
1039 void HTMLMediaElement::load()
1040 {
1041     Ref<HTMLMediaElement> protect(*this); // loadInternal may result in a 'beforeload' event, which can make arbitrary DOM mutations.
1042     
1043     LOG(Media, "HTMLMediaElement::load(%p)", this);
1044     
1045     if (!m_mediaSession->dataLoadingPermitted(*this))
1046         return;
1047     if (ScriptController::processingUserGestureForMedia())
1048         removeBehaviorsRestrictionsAfterFirstUserGesture();
1049
1050     prepareForLoad();
1051     loadInternal();
1052     prepareToPlay();
1053 }
1054
1055 void HTMLMediaElement::prepareForLoad()
1056 {
1057     LOG(Media, "HTMLMediaElement::prepareForLoad(%p)", this);
1058
1059     // Perform the cleanup required for the resource load algorithm to run.
1060     stopPeriodicTimers();
1061     m_pendingActionTimer.stop();
1062     // FIXME: Figure out appropriate place to reset LoadTextTrackResource if necessary and set m_pendingActionFlags to 0 here.
1063     m_pendingActionFlags &= ~LoadMediaResource;
1064     m_sentEndEvent = false;
1065     m_sentStalledEvent = false;
1066     m_haveFiredLoadedData = false;
1067     m_completelyLoaded = false;
1068     m_havePreparedToPlay = false;
1069     m_displayMode = Unknown;
1070     m_currentSrc = URL();
1071
1072 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1073     m_failedToPlayToWirelessTarget = false;
1074 #endif
1075
1076     // 1 - Abort any already-running instance of the resource selection algorithm for this element.
1077     m_loadState = WaitingForSource;
1078     m_currentSourceNode = nullptr;
1079
1080     // 2 - If there are any tasks from the media element's media element event task source in 
1081     // one of the task queues, then remove those tasks.
1082     cancelPendingEventsAndCallbacks();
1083
1084     // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
1085     // a task to fire a simple event named abort at the media element.
1086     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
1087         scheduleEvent(eventNames().abortEvent);
1088
1089 #if ENABLE(MEDIA_SOURCE)
1090     closeMediaSource();
1091 #endif
1092
1093     createMediaPlayer();
1094
1095     // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
1096     if (m_networkState != NETWORK_EMPTY) {
1097         // 4.1 - Queue a task to fire a simple event named emptied at the media element.
1098         scheduleEvent(eventNames().emptiedEvent);
1099
1100         // 4.2 - If a fetching process is in progress for the media element, the user agent should stop it.
1101         m_networkState = NETWORK_EMPTY;
1102
1103         // 4.3 - Forget the media element's media-resource-specific tracks.
1104         forgetResourceSpecificTracks();
1105
1106         // 4.4 - If readyState is not set to HAVE_NOTHING, then set it to that state.
1107         m_readyState = HAVE_NOTHING;
1108         m_readyStateMaximum = HAVE_NOTHING;
1109
1110         // 4.5 - If the paused attribute is false, then set it to true.
1111         m_paused = true;
1112
1113         // 4.6 - If seeking is true, set it to false.
1114         clearSeeking();
1115
1116         // 4.7 - Set the current playback position to 0.
1117         //       Set the official playback position to 0.
1118         //       If this changed the official playback position, then queue a task to fire a simple event named timeupdate at the media element.
1119         // FIXME: Add support for firing this event. e.g., scheduleEvent(eventNames().timeUpdateEvent);
1120
1121         // 4.8 - Set the initial playback position to 0.
1122         // FIXME: Make this less subtle. The position only becomes 0 because of the createMediaPlayer() call
1123         // above.
1124         refreshCachedTime();
1125
1126         invalidateCachedTime();
1127
1128         // 4.9 - Set the timeline offset to Not-a-Number (NaN).
1129         // 4.10 - Update the duration attribute to Not-a-Number (NaN).
1130
1131         updateMediaController();
1132 #if ENABLE(VIDEO_TRACK)
1133         updateActiveTextTrackCues(MediaTime::zeroTime());
1134 #endif
1135     }
1136
1137     // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
1138     setPlaybackRate(defaultPlaybackRate());
1139
1140     // 6 - Set the error attribute to null and the autoplaying flag to true.
1141     m_error = nullptr;
1142     m_autoplaying = true;
1143     mediaSession().clientWillBeginAutoplaying();
1144
1145     // 7 - Invoke the media element's resource selection algorithm.
1146
1147     // 8 - Note: Playback of any previously playing media resource for this element stops.
1148
1149     // The resource selection algorithm
1150     // 1 - Set the networkState to NETWORK_NO_SOURCE
1151     m_networkState = NETWORK_NO_SOURCE;
1152
1153     // 2 - Asynchronously await a stable state.
1154
1155     m_playedTimeRanges = TimeRanges::create();
1156
1157     // FIXME: Investigate whether these can be moved into m_networkState != NETWORK_EMPTY block above
1158     // so they are closer to the relevant spec steps.
1159     m_lastSeekTime = MediaTime::zeroTime();
1160
1161     // The spec doesn't say to block the load event until we actually run the asynchronous section
1162     // algorithm, but do it now because we won't start that until after the timer fires and the 
1163     // event may have already fired by then.
1164     MediaPlayer::Preload effectivePreload = m_mediaSession->effectivePreloadForElement(*this);
1165     if (effectivePreload != MediaPlayer::None)
1166         setShouldDelayLoadEvent(true);
1167
1168 #if PLATFORM(IOS)
1169     if (effectivePreload != MediaPlayer::None && m_mediaSession->allowsAutomaticMediaDataLoading(*this))
1170         prepareToPlay();
1171 #endif
1172
1173     configureMediaControls();
1174 }
1175
1176 void HTMLMediaElement::loadInternal()
1177 {
1178     LOG(Media, "HTMLMediaElement::loadInternal(%p)", this);
1179
1180     // Some of the code paths below this function dispatch the BeforeLoad event. This ASSERT helps
1181     // us catch those bugs more quickly without needing all the branches to align to actually
1182     // trigger the event.
1183     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
1184
1185     // If we can't start a load right away, start it later.
1186     if (!m_mediaSession->pageAllowsDataLoading(*this)) {
1187         LOG(Media, "HTMLMediaElement::loadInternal(%p) - not allowed to load in background, waiting", this);
1188         setShouldDelayLoadEvent(false);
1189         if (m_isWaitingUntilMediaCanStart)
1190             return;
1191         m_isWaitingUntilMediaCanStart = true;
1192         document().addMediaCanStartListener(this);
1193         return;
1194     }
1195
1196     clearFlags(m_pendingActionFlags, LoadMediaResource);
1197
1198     // Once the page has allowed an element to load media, it is free to load at will. This allows a 
1199     // playlist that starts in a foreground tab to continue automatically if the tab is subsequently 
1200     // put into the background.
1201     m_mediaSession->removeBehaviorRestriction(MediaElementSession::RequirePageConsentToLoadMedia);
1202
1203 #if ENABLE(VIDEO_TRACK)
1204     if (hasMediaControls())
1205         mediaControls()->changedClosedCaptionsVisibility();
1206
1207     // HTMLMediaElement::textTracksAreReady will need "... the text tracks whose mode was not in the
1208     // disabled state when the element's resource selection algorithm last started".
1209     m_textTracksWhenResourceSelectionBegan.clear();
1210     if (m_textTracks) {
1211         for (unsigned i = 0; i < m_textTracks->length(); ++i) {
1212             TextTrack* track = m_textTracks->item(i);
1213             if (track->mode() != TextTrack::Mode::Disabled)
1214                 m_textTracksWhenResourceSelectionBegan.append(track);
1215         }
1216     }
1217 #endif
1218
1219     selectMediaResource();
1220 }
1221
1222 void HTMLMediaElement::selectMediaResource()
1223 {
1224     LOG(Media, "HTMLMediaElement::selectMediaResource(%p)", this);
1225
1226     ASSERT(m_player);
1227     if (!m_player)
1228         return;
1229
1230     enum Mode { attribute, children };
1231
1232     // 3 - If the media element has a src attribute, then let mode be attribute.
1233     Mode mode = attribute;
1234     if (!fastHasAttribute(srcAttr)) {
1235         // Otherwise, if the media element does not have a src attribute but has a source 
1236         // element child, then let mode be children and let candidate be the first such 
1237         // source element child in tree order.
1238         if (auto firstSource = childrenOfType<HTMLSourceElement>(*this).first()) {
1239             mode = children;
1240             m_nextChildNodeToConsider = firstSource;
1241             m_currentSourceNode = nullptr;
1242         } else {
1243             // Otherwise the media element has neither a src attribute nor a source element 
1244             // child: set the networkState to NETWORK_EMPTY, and abort these steps; the 
1245             // synchronous section ends.
1246             m_loadState = WaitingForSource;
1247             setShouldDelayLoadEvent(false);
1248             m_networkState = NETWORK_EMPTY;
1249
1250             LOG(Media, "HTMLMediaElement::selectMediaResource(%p) - nothing to load", this);
1251             return;
1252         }
1253     }
1254
1255     // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event), 
1256     // and set its networkState to NETWORK_LOADING.
1257     setShouldDelayLoadEvent(true);
1258     m_networkState = NETWORK_LOADING;
1259
1260     // 5 - Queue a task to fire a simple event named loadstart at the media element.
1261     scheduleEvent(eventNames().loadstartEvent);
1262
1263     // 6 - If mode is attribute, then run these substeps
1264     if (mode == attribute) {
1265         m_loadState = LoadingFromSrcAttr;
1266
1267         // If the src attribute's value is the empty string ... jump down to the failed step below
1268         URL mediaURL = getNonEmptyURLAttribute(srcAttr);
1269         if (mediaURL.isEmpty()) {
1270             mediaLoadingFailed(MediaPlayer::FormatError);
1271             LOG(Media, "HTMLMediaElement::selectMediaResource(%p) -  empty 'src'", this);
1272             return;
1273         }
1274
1275         if (!isSafeToLoadURL(mediaURL, Complain) || !dispatchBeforeLoadEvent(mediaURL.string())) {
1276             mediaLoadingFailed(MediaPlayer::FormatError);
1277             return;
1278         }
1279
1280         // No type or key system information is available when the url comes
1281         // from the 'src' attribute so MediaPlayer
1282         // will have to pick a media engine based on the file extension.
1283         ContentType contentType((String()));
1284         loadResource(mediaURL, contentType, String());
1285         LOG(Media, "HTMLMediaElement::selectMediaResource(%p) - using 'src' attribute url", this);
1286         return;
1287     }
1288
1289     // Otherwise, the source elements will be used
1290     loadNextSourceChild();
1291 }
1292
1293 void HTMLMediaElement::loadNextSourceChild()
1294 {
1295     ContentType contentType((String()));
1296     String keySystem;
1297     URL mediaURL = selectNextSourceChild(&contentType, &keySystem, Complain);
1298     if (!mediaURL.isValid()) {
1299         waitForSourceChange();
1300         return;
1301     }
1302
1303     // Recreate the media player for the new url
1304     createMediaPlayer();
1305
1306     m_loadState = LoadingFromSourceElement;
1307     loadResource(mediaURL, contentType, keySystem);
1308 }
1309
1310 void HTMLMediaElement::loadResource(const URL& initialURL, ContentType& contentType, const String& keySystem)
1311 {
1312     ASSERT(isSafeToLoadURL(initialURL, Complain));
1313
1314     LOG(Media, "HTMLMediaElement::loadResource(%p) - %s, %s, %s", this, urlForLoggingMedia(initialURL).utf8().data(), contentType.raw().utf8().data(), keySystem.utf8().data());
1315
1316     Frame* frame = document().frame();
1317     if (!frame) {
1318         mediaLoadingFailed(MediaPlayer::FormatError);
1319         return;
1320     }
1321
1322     Page* page = frame->page();
1323     if (!page) {
1324         mediaLoadingFailed(MediaPlayer::FormatError);
1325         return;
1326     }
1327
1328     URL url = initialURL;
1329     if (!frame->loader().willLoadMediaElementURL(url)) {
1330         mediaLoadingFailed(MediaPlayer::FormatError);
1331         return;
1332     }
1333
1334 #if ENABLE(CONTENT_EXTENSIONS)
1335     ResourceRequest request(url);
1336     DocumentLoader* documentLoader = frame->loader().documentLoader();
1337
1338     if (documentLoader && page->userContentProvider().processContentExtensionRulesForLoad(request, ResourceType::Media, *documentLoader) == ContentExtensions::BlockedStatus::Blocked) {
1339         request = { };
1340         mediaLoadingFailed(MediaPlayer::FormatError);
1341         return;
1342     }
1343 #endif
1344
1345     // The resource fetch algorithm 
1346     m_networkState = NETWORK_LOADING;
1347
1348     // If the url should be loaded from the application cache, pass the url of the cached file
1349     // to the media engine.
1350     ApplicationCacheHost* cacheHost = frame->loader().documentLoader()->applicationCacheHost();
1351     ApplicationCacheResource* resource = 0;
1352     if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(url), resource)) {
1353         // Resources that are not present in the manifest will always fail to load (at least, after the
1354         // cache has been primed the first time), making the testing of offline applications simpler.
1355         if (!resource || resource->path().isEmpty()) {
1356             mediaLoadingFailed(MediaPlayer::NetworkError);
1357             return;
1358         }
1359     }
1360
1361     // Log that we started loading a media element.
1362     page->diagnosticLoggingClient().logDiagnosticMessageWithValue(DiagnosticLoggingKeys::mediaKey(), isVideo() ? DiagnosticLoggingKeys::videoKey() : DiagnosticLoggingKeys::audioKey(), DiagnosticLoggingKeys::loadingKey(), ShouldSample::No);
1363
1364     m_firstTimePlaying = true;
1365
1366     // Set m_currentSrc *before* changing to the cache url, the fact that we are loading from the app
1367     // cache is an internal detail not exposed through the media element API.
1368     m_currentSrc = url;
1369
1370     if (resource) {
1371         url = ApplicationCacheHost::createFileURL(resource->path());
1372         LOG(Media, "HTMLMediaElement::loadResource(%p) - will load from app cache -> %s", this, urlForLoggingMedia(url).utf8().data());
1373     }
1374
1375     LOG(Media, "HTMLMediaElement::loadResource(%p) - m_currentSrc -> %s", this, urlForLoggingMedia(m_currentSrc).utf8().data());
1376
1377     if (m_sendProgressEvents)
1378         startProgressEventTimer();
1379
1380     bool privateMode = document().page() && document().page()->usesEphemeralSession();
1381     m_player->setPrivateBrowsingMode(privateMode);
1382
1383     // Reset display mode to force a recalculation of what to show because we are resetting the player.
1384     setDisplayMode(Unknown);
1385
1386     if (!autoplay())
1387         m_player->setPreload(m_mediaSession->effectivePreloadForElement(*this));
1388     m_player->setPreservesPitch(m_webkitPreservesPitch);
1389
1390     if (!m_explicitlyMuted) {
1391         m_explicitlyMuted = true;
1392         m_muted = fastHasAttribute(mutedAttr);
1393     }
1394
1395     updateVolume();
1396
1397     bool loadAttempted = false;
1398 #if ENABLE(MEDIA_SOURCE)
1399     ASSERT(!m_mediaSource);
1400
1401     if (url.protocolIs(mediaSourceBlobProtocol))
1402         m_mediaSource = MediaSource::lookup(url.string());
1403
1404     if (m_mediaSource) {
1405         if (m_mediaSource->attachToElement(this))
1406             m_player->load(url, contentType, m_mediaSource.get());
1407         else {
1408             // Forget our reference to the MediaSource, so we leave it alone
1409             // while processing remainder of load failure.
1410             m_mediaSource = nullptr;
1411             mediaLoadingFailed(MediaPlayer::FormatError);
1412         }
1413         loadAttempted = true;
1414     }
1415 #endif
1416
1417 #if ENABLE(MEDIA_STREAM)
1418     if (!loadAttempted) {
1419         if (!m_mediaStreamSrcObject && url.protocolIs(mediaStreamBlobProtocol))
1420             m_mediaStreamSrcObject = MediaStreamRegistry::shared().lookUp(url);
1421
1422         if (m_mediaStreamSrcObject) {
1423             loadAttempted = true;
1424             if (!m_player->load(m_mediaStreamSrcObject->privateStream()))
1425                 mediaLoadingFailed(MediaPlayer::FormatError);
1426         }
1427     }
1428 #endif
1429
1430     if (!loadAttempted && !m_player->load(url, contentType, keySystem))
1431         mediaLoadingFailed(MediaPlayer::FormatError);
1432
1433     // If there is no poster to display, allow the media engine to render video frames as soon as
1434     // they are available.
1435     updateDisplayState();
1436
1437     if (renderer())
1438         renderer()->updateFromElement();
1439 }
1440
1441 #if ENABLE(VIDEO_TRACK)
1442 static bool trackIndexCompare(TextTrack* a,
1443                               TextTrack* b)
1444 {
1445     return a->trackIndex() - b->trackIndex() < 0;
1446 }
1447
1448 static bool eventTimeCueCompare(const std::pair<MediaTime, TextTrackCue*>& a, const std::pair<MediaTime, TextTrackCue*>& b)
1449 {
1450     // 12 - Sort the tasks in events in ascending time order (tasks with earlier
1451     // times first).
1452     if (a.first != b.first)
1453         return a.first - b.first < MediaTime::zeroTime();
1454
1455     // If the cues belong to different text tracks, it doesn't make sense to
1456     // compare the two tracks by the relative cue order, so return the relative
1457     // track order.
1458     if (a.second->track() != b.second->track())
1459         return trackIndexCompare(a.second->track(), b.second->track());
1460
1461     // 12 - Further sort tasks in events that have the same time by the
1462     // relative text track cue order of the text track cues associated
1463     // with these tasks.
1464     return a.second->cueIndex() - b.second->cueIndex() < 0;
1465 }
1466
1467 static bool compareCueInterval(const CueInterval& one, const CueInterval& two)
1468 {
1469     return one.data()->isOrderedBefore(two.data());
1470 };
1471
1472
1473 void HTMLMediaElement::updateActiveTextTrackCues(const MediaTime& movieTime)
1474 {
1475     // 4.8.10.8 Playing the media resource
1476
1477     //  If the current playback position changes while the steps are running,
1478     //  then the user agent must wait for the steps to complete, and then must
1479     //  immediately rerun the steps.
1480     if (ignoreTrackDisplayUpdateRequests())
1481         return;
1482
1483     LOG(Media, "HTMLMediaElement::updateActiveTextTrackCues(%p)", this);
1484
1485     // 1 - Let current cues be a list of cues, initialized to contain all the
1486     // cues of all the hidden, showing, or showing by default text tracks of the
1487     // media element (not the disabled ones) whose start times are less than or
1488     // equal to the current playback position and whose end times are greater
1489     // than the current playback position.
1490     CueList currentCues;
1491
1492     // The user agent must synchronously unset [the text track cue active] flag
1493     // whenever ... the media element's readyState is changed back to HAVE_NOTHING.
1494     if (m_readyState != HAVE_NOTHING && m_player) {
1495         currentCues = m_cueTree.allOverlaps(m_cueTree.createInterval(movieTime, movieTime));
1496         if (currentCues.size() > 1)
1497             std::sort(currentCues.begin(), currentCues.end(), &compareCueInterval);
1498     }
1499
1500     CueList previousCues;
1501     CueList missedCues;
1502
1503     // 2 - Let other cues be a list of cues, initialized to contain all the cues
1504     // of hidden, showing, and showing by default text tracks of the media
1505     // element that are not present in current cues.
1506     previousCues = m_currentlyActiveCues;
1507
1508     // 3 - Let last time be the current playback position at the time this
1509     // algorithm was last run for this media element, if this is not the first
1510     // time it has run.
1511     MediaTime lastTime = m_lastTextTrackUpdateTime;
1512
1513     // 4 - If the current playback position has, since the last time this
1514     // algorithm was run, only changed through its usual monotonic increase
1515     // during normal playback, then let missed cues be the list of cues in other
1516     // cues whose start times are greater than or equal to last time and whose
1517     // end times are less than or equal to the current playback position.
1518     // Otherwise, let missed cues be an empty list.
1519     if (lastTime >= MediaTime::zeroTime() && m_lastSeekTime < movieTime) {
1520         CueList potentiallySkippedCues =
1521             m_cueTree.allOverlaps(m_cueTree.createInterval(lastTime, movieTime));
1522
1523         for (size_t i = 0; i < potentiallySkippedCues.size(); ++i) {
1524             MediaTime cueStartTime = potentiallySkippedCues[i].low();
1525             MediaTime cueEndTime = potentiallySkippedCues[i].high();
1526
1527             // Consider cues that may have been missed since the last seek time.
1528             if (cueStartTime > std::max(m_lastSeekTime, lastTime) && cueEndTime < movieTime)
1529                 missedCues.append(potentiallySkippedCues[i]);
1530         }
1531     }
1532
1533     m_lastTextTrackUpdateTime = movieTime;
1534
1535     // 5 - If the time was reached through the usual monotonic increase of the
1536     // current playback position during normal playback, and if the user agent
1537     // has not fired a timeupdate event at the element in the past 15 to 250ms
1538     // and is not still running event handlers for such an event, then the user
1539     // agent must queue a task to fire a simple event named timeupdate at the
1540     // element. (In the other cases, such as explicit seeks, relevant events get
1541     // fired as part of the overall process of changing the current playback
1542     // position.)
1543     if (!m_paused && m_lastSeekTime <= lastTime)
1544         scheduleTimeupdateEvent(false);
1545
1546     // Explicitly cache vector sizes, as their content is constant from here.
1547     size_t currentCuesSize = currentCues.size();
1548     size_t missedCuesSize = missedCues.size();
1549     size_t previousCuesSize = previousCues.size();
1550
1551     // 6 - If all of the cues in current cues have their text track cue active
1552     // flag set, none of the cues in other cues have their text track cue active
1553     // flag set, and missed cues is empty, then abort these steps.
1554     bool activeSetChanged = missedCuesSize;
1555
1556     for (size_t i = 0; !activeSetChanged && i < previousCuesSize; ++i)
1557         if (!currentCues.contains(previousCues[i]) && previousCues[i].data()->isActive())
1558             activeSetChanged = true;
1559
1560     for (size_t i = 0; i < currentCuesSize; ++i) {
1561         TextTrackCue* cue = currentCues[i].data();
1562
1563         if (cue->isRenderable())
1564             toVTTCue(cue)->updateDisplayTree(movieTime);
1565
1566         if (!cue->isActive())
1567             activeSetChanged = true;
1568     }
1569
1570     if (!activeSetChanged)
1571         return;
1572
1573     // 7 - If the time was reached through the usual monotonic increase of the
1574     // current playback position during normal playback, and there are cues in
1575     // other cues that have their text track cue pause-on-exi flag set and that
1576     // either have their text track cue active flag set or are also in missed
1577     // cues, then immediately pause the media element.
1578     for (size_t i = 0; !m_paused && i < previousCuesSize; ++i) {
1579         if (previousCues[i].data()->pauseOnExit()
1580             && previousCues[i].data()->isActive()
1581             && !currentCues.contains(previousCues[i]))
1582             pause();
1583     }
1584
1585     for (size_t i = 0; !m_paused && i < missedCuesSize; ++i) {
1586         if (missedCues[i].data()->pauseOnExit())
1587             pause();
1588     }
1589
1590     // 8 - Let events be a list of tasks, initially empty. Each task in this
1591     // list will be associated with a text track, a text track cue, and a time,
1592     // which are used to sort the list before the tasks are queued.
1593     Vector<std::pair<MediaTime, TextTrackCue*>> eventTasks;
1594
1595     // 8 - Let affected tracks be a list of text tracks, initially empty.
1596     Vector<TextTrack*> affectedTracks;
1597
1598     for (size_t i = 0; i < missedCuesSize; ++i) {
1599         // 9 - For each text track cue in missed cues, prepare an event named enter
1600         // for the TextTrackCue object with the text track cue start time.
1601         eventTasks.append(std::make_pair(missedCues[i].data()->startMediaTime(),
1602                                          missedCues[i].data()));
1603
1604         // 10 - For each text track [...] in missed cues, prepare an event
1605         // named exit for the TextTrackCue object with the  with the later of
1606         // the text track cue end time and the text track cue start time.
1607
1608         // Note: An explicit task is added only if the cue is NOT a zero or
1609         // negative length cue. Otherwise, the need for an exit event is
1610         // checked when these tasks are actually queued below. This doesn't
1611         // affect sorting events before dispatch either, because the exit
1612         // event has the same time as the enter event.
1613         if (missedCues[i].data()->startMediaTime() < missedCues[i].data()->endMediaTime())
1614             eventTasks.append(std::make_pair(missedCues[i].data()->endMediaTime(), missedCues[i].data()));
1615     }
1616
1617     for (size_t i = 0; i < previousCuesSize; ++i) {
1618         // 10 - For each text track cue in other cues that has its text
1619         // track cue active flag set prepare an event named exit for the
1620         // TextTrackCue object with the text track cue end time.
1621         if (!currentCues.contains(previousCues[i]))
1622             eventTasks.append(std::make_pair(previousCues[i].data()->endMediaTime(),
1623                                              previousCues[i].data()));
1624     }
1625
1626     for (size_t i = 0; i < currentCuesSize; ++i) {
1627         // 11 - For each text track cue in current cues that does not have its
1628         // text track cue active flag set, prepare an event named enter for the
1629         // TextTrackCue object with the text track cue start time.
1630         if (!previousCues.contains(currentCues[i]))
1631             eventTasks.append(std::make_pair(currentCues[i].data()->startMediaTime(),
1632                                              currentCues[i].data()));
1633     }
1634
1635     // 12 - Sort the tasks in events in ascending time order (tasks with earlier
1636     // times first).
1637     std::sort(eventTasks.begin(), eventTasks.end(), eventTimeCueCompare);
1638
1639     for (size_t i = 0; i < eventTasks.size(); ++i) {
1640         if (!affectedTracks.contains(eventTasks[i].second->track()))
1641             affectedTracks.append(eventTasks[i].second->track());
1642
1643         // 13 - Queue each task in events, in list order.
1644         RefPtr<Event> event;
1645
1646         // Each event in eventTasks may be either an enterEvent or an exitEvent,
1647         // depending on the time that is associated with the event. This
1648         // correctly identifies the type of the event, if the startTime is
1649         // less than the endTime in the cue.
1650         if (eventTasks[i].second->startTime() >= eventTasks[i].second->endTime()) {
1651             event = Event::create(eventNames().enterEvent, false, false);
1652             event->setTarget(eventTasks[i].second);
1653             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1654
1655             event = Event::create(eventNames().exitEvent, false, false);
1656             event->setTarget(eventTasks[i].second);
1657             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1658         } else {
1659             if (eventTasks[i].first == eventTasks[i].second->startMediaTime())
1660                 event = Event::create(eventNames().enterEvent, false, false);
1661             else
1662                 event = Event::create(eventNames().exitEvent, false, false);
1663
1664             event->setTarget(eventTasks[i].second);
1665             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1666         }
1667     }
1668
1669     // 14 - Sort affected tracks in the same order as the text tracks appear in
1670     // the media element's list of text tracks, and remove duplicates.
1671     std::sort(affectedTracks.begin(), affectedTracks.end(), trackIndexCompare);
1672
1673     // 15 - For each text track in affected tracks, in the list order, queue a
1674     // task to fire a simple event named cuechange at the TextTrack object, and, ...
1675     for (size_t i = 0; i < affectedTracks.size(); ++i) {
1676         RefPtr<Event> event = Event::create(eventNames().cuechangeEvent, false, false);
1677         event->setTarget(affectedTracks[i]);
1678
1679         m_asyncEventQueue.enqueueEvent(WTFMove(event));
1680
1681         // ... if the text track has a corresponding track element, to then fire a
1682         // simple event named cuechange at the track element as well.
1683         if (is<LoadableTextTrack>(*affectedTracks[i])) {
1684             RefPtr<Event> event = Event::create(eventNames().cuechangeEvent, false, false);
1685             HTMLTrackElement* trackElement = downcast<LoadableTextTrack>(*affectedTracks[i]).trackElement();
1686             ASSERT(trackElement);
1687             event->setTarget(trackElement);
1688             
1689             m_asyncEventQueue.enqueueEvent(WTFMove(event));
1690         }
1691     }
1692
1693     // 16 - Set the text track cue active flag of all the cues in the current
1694     // cues, and unset the text track cue active flag of all the cues in the
1695     // other cues.
1696     for (size_t i = 0; i < currentCuesSize; ++i)
1697         currentCues[i].data()->setIsActive(true);
1698
1699     for (size_t i = 0; i < previousCuesSize; ++i)
1700         if (!currentCues.contains(previousCues[i]))
1701             previousCues[i].data()->setIsActive(false);
1702
1703     // Update the current active cues.
1704     m_currentlyActiveCues = currentCues;
1705
1706     if (activeSetChanged)
1707         updateTextTrackDisplay();
1708 }
1709
1710 bool HTMLMediaElement::textTracksAreReady() const
1711 {
1712     // 4.8.10.12.1 Text track model
1713     // ...
1714     // The text tracks of a media element are ready if all the text tracks whose mode was not 
1715     // in the disabled state when the element's resource selection algorithm last started now
1716     // have a text track readiness state of loaded or failed to load.
1717     for (unsigned i = 0; i < m_textTracksWhenResourceSelectionBegan.size(); ++i) {
1718         if (m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::Loading
1719             || m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::NotLoaded)
1720             return false;
1721     }
1722
1723     return true;
1724 }
1725
1726 void HTMLMediaElement::textTrackReadyStateChanged(TextTrack* track)
1727 {
1728     if (m_player && m_textTracksWhenResourceSelectionBegan.contains(track)) {
1729         if (track->readinessState() != TextTrack::Loading)
1730             setReadyState(m_player->readyState());
1731     } else {
1732         // The track readiness state might have changed as a result of the user
1733         // clicking the captions button. In this case, a check whether all the
1734         // resources have failed loading should be done in order to hide the CC button.
1735         if (hasMediaControls() && track->readinessState() == TextTrack::FailedToLoad)
1736             mediaControls()->refreshClosedCaptionsButtonVisibility();
1737     }
1738 }
1739
1740 void HTMLMediaElement::audioTrackEnabledChanged(AudioTrack* track)
1741 {
1742     if (m_audioTracks && m_audioTracks->contains(track))
1743         m_audioTracks->scheduleChangeEvent();
1744 }
1745
1746 void HTMLMediaElement::textTrackModeChanged(TextTrack* track)
1747 {
1748     bool trackIsLoaded = true;
1749     if (track->trackType() == TextTrack::TrackElement) {
1750         trackIsLoaded = false;
1751         for (auto& trackElement : childrenOfType<HTMLTrackElement>(*this)) {
1752             if (trackElement.track() == track) {
1753                 if (trackElement.readyState() == HTMLTrackElement::LOADING || trackElement.readyState() == HTMLTrackElement::LOADED)
1754                     trackIsLoaded = true;
1755                 break;
1756             }
1757         }
1758     }
1759
1760     // If this is the first added track, create the list of text tracks.
1761     if (!m_textTracks)
1762         m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
1763     
1764     // Mark this track as "configured" so configureTextTracks won't change the mode again.
1765     track->setHasBeenConfigured(true);
1766     
1767     if (track->mode() != TextTrack::Mode::Disabled && trackIsLoaded)
1768         textTrackAddCues(track, track->cues());
1769
1770     configureTextTrackDisplay(AssumeTextTrackVisibilityChanged);
1771
1772     if (m_textTracks && m_textTracks->contains(track))
1773         m_textTracks->scheduleChangeEvent();
1774
1775 #if ENABLE(AVF_CAPTIONS)
1776     if (track->trackType() == TextTrack::TrackElement && m_player)
1777         m_player->notifyTrackModeChanged();
1778 #endif
1779 }
1780
1781 void HTMLMediaElement::videoTrackSelectedChanged(VideoTrack* track)
1782 {
1783     if (m_videoTracks && m_videoTracks->contains(track))
1784         m_videoTracks->scheduleChangeEvent();
1785 }
1786
1787 void HTMLMediaElement::textTrackKindChanged(TextTrack* track)
1788 {
1789     if (track->kind() != TextTrack::Kind::Captions && track->kind() != TextTrack::Kind::Subtitles && track->mode() == TextTrack::Mode::Showing)
1790         track->setMode(TextTrack::Mode::Hidden);
1791 }
1792
1793 void HTMLMediaElement::beginIgnoringTrackDisplayUpdateRequests()
1794 {
1795     ++m_ignoreTrackDisplayUpdate;
1796 }
1797
1798 void HTMLMediaElement::endIgnoringTrackDisplayUpdateRequests()
1799 {
1800     ASSERT(m_ignoreTrackDisplayUpdate);
1801     --m_ignoreTrackDisplayUpdate;
1802     if (!m_ignoreTrackDisplayUpdate && m_inActiveDocument)
1803         updateActiveTextTrackCues(currentMediaTime());
1804 }
1805
1806 void HTMLMediaElement::textTrackAddCues(TextTrack* track, const TextTrackCueList* cues) 
1807 {
1808     if (track->mode() == TextTrack::Mode::Disabled)
1809         return;
1810
1811     TrackDisplayUpdateScope scope(this);
1812     for (size_t i = 0; i < cues->length(); ++i)
1813         textTrackAddCue(track, cues->item(i));
1814 }
1815
1816 void HTMLMediaElement::textTrackRemoveCues(TextTrack*, const TextTrackCueList* cues) 
1817 {
1818     TrackDisplayUpdateScope scope(this);
1819     for (size_t i = 0; i < cues->length(); ++i)
1820         textTrackRemoveCue(cues->item(i)->track(), cues->item(i));
1821 }
1822
1823 void HTMLMediaElement::textTrackAddCue(TextTrack* track, PassRefPtr<TextTrackCue> prpCue)
1824 {
1825     if (track->mode() == TextTrack::Mode::Disabled)
1826         return;
1827
1828     RefPtr<TextTrackCue> cue = prpCue;
1829
1830     // Negative duration cues need be treated in the interval tree as
1831     // zero-length cues.
1832     MediaTime endTime = std::max(cue->startMediaTime(), cue->endMediaTime());
1833
1834     CueInterval interval = m_cueTree.createInterval(cue->startMediaTime(), endTime, cue.get());
1835     if (!m_cueTree.contains(interval))
1836         m_cueTree.add(interval);
1837     updateActiveTextTrackCues(currentMediaTime());
1838 }
1839
1840 void HTMLMediaElement::textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue> prpCue)
1841 {
1842     RefPtr<TextTrackCue> cue = prpCue;
1843     // Negative duration cues need to be treated in the interval tree as
1844     // zero-length cues.
1845     MediaTime endTime = std::max(cue->startMediaTime(), cue->endMediaTime());
1846
1847     CueInterval interval = m_cueTree.createInterval(cue->startMediaTime(), endTime, cue.get());
1848     m_cueTree.remove(interval);
1849
1850     // Since the cue will be removed from the media element and likely the
1851     // TextTrack might also be destructed, notifying the region of the cue
1852     // removal shouldn't be done.
1853     if (cue->isRenderable())
1854         toVTTCue(cue.get())->notifyRegionWhenRemovingDisplayTree(false);
1855
1856     size_t index = m_currentlyActiveCues.find(interval);
1857     if (index != notFound) {
1858         cue->setIsActive(false);
1859         m_currentlyActiveCues.remove(index);
1860     }
1861
1862     if (cue->isRenderable())
1863         toVTTCue(cue.get())->removeDisplayTree();
1864     updateActiveTextTrackCues(currentMediaTime());
1865
1866     if (cue->isRenderable())
1867         toVTTCue(cue.get())->notifyRegionWhenRemovingDisplayTree(true);
1868 }
1869
1870 #endif
1871
1872 bool HTMLMediaElement::isSafeToLoadURL(const URL& url, InvalidURLAction actionIfInvalid)
1873 {
1874     if (!url.isValid()) {
1875         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%p) - %s -> FALSE because url is invalid", this, urlForLoggingMedia(url).utf8().data());
1876         return false;
1877     }
1878
1879     Frame* frame = document().frame();
1880     if (!frame || !document().securityOrigin()->canDisplay(url)) {
1881         if (actionIfInvalid == Complain)
1882             FrameLoader::reportLocalLoadFailed(frame, url.stringCenterEllipsizedToLength());
1883         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%p) - %s -> FALSE rejected by SecurityOrigin", this, urlForLoggingMedia(url).utf8().data());
1884         return false;
1885     }
1886
1887     if (!document().contentSecurityPolicy()->allowMediaFromSource(url, isInUserAgentShadowTree())) {
1888         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%p) - %s -> rejected by Content Security Policy", this, urlForLoggingMedia(url).utf8().data());
1889         return false;
1890     }
1891
1892     return true;
1893 }
1894
1895 void HTMLMediaElement::startProgressEventTimer()
1896 {
1897     if (m_progressEventTimer.isActive())
1898         return;
1899
1900     m_previousProgressTime = monotonicallyIncreasingTime();
1901     // 350ms is not magic, it is in the spec!
1902     m_progressEventTimer.startRepeating(0.350);
1903 }
1904
1905 void HTMLMediaElement::waitForSourceChange()
1906 {
1907     LOG(Media, "HTMLMediaElement::waitForSourceChange(%p)", this);
1908
1909     stopPeriodicTimers();
1910     m_loadState = WaitingForSource;
1911
1912     // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
1913     m_networkState = NETWORK_NO_SOURCE;
1914
1915     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1916     setShouldDelayLoadEvent(false);
1917
1918     updateDisplayState();
1919
1920     if (renderer())
1921         renderer()->updateFromElement();
1922 }
1923
1924 void HTMLMediaElement::noneSupported()
1925 {
1926     LOG(Media, "HTMLMediaElement::noneSupported(%p)", this);
1927
1928     stopPeriodicTimers();
1929     m_loadState = WaitingForSource;
1930     m_currentSourceNode = nullptr;
1931
1932     // 4.8.10.5 
1933     // 6 - Reaching this step indicates that the media resource failed to load or that the given 
1934     // URL could not be resolved. In one atomic operation, run the following steps:
1935
1936     // 6.1 - Set the error attribute to a new MediaError object whose code attribute is set to
1937     // MEDIA_ERR_SRC_NOT_SUPPORTED.
1938     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
1939
1940     // 6.2 - Forget the media element's media-resource-specific text tracks.
1941     forgetResourceSpecificTracks();
1942
1943     // 6.3 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
1944     m_networkState = NETWORK_NO_SOURCE;
1945
1946     // 7 - Queue a task to fire a simple event named error at the media element.
1947     scheduleEvent(eventNames().errorEvent);
1948
1949     rejectPendingPlayPromises(DOMError::create("NotSupportedError", "The operation is not supported."));
1950
1951 #if ENABLE(MEDIA_SOURCE)
1952     closeMediaSource();
1953 #endif
1954
1955     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1956     setShouldDelayLoadEvent(false);
1957
1958     // 9 - Abort these steps. Until the load() method is invoked or the src attribute is changed, 
1959     // the element won't attempt to load another resource.
1960
1961     updateDisplayState();
1962
1963     if (renderer())
1964         renderer()->updateFromElement();
1965 }
1966
1967 void HTMLMediaElement::mediaLoadingFailedFatally(MediaPlayer::NetworkState error)
1968 {
1969     LOG(Media, "HTMLMediaElement::mediaLoadingFailedFatally(%p) - error = %d", this, static_cast<int>(error));
1970
1971     // 1 - The user agent should cancel the fetching process.
1972     stopPeriodicTimers();
1973     m_loadState = WaitingForSource;
1974
1975     // 2 - Set the error attribute to a new MediaError object whose code attribute is 
1976     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
1977     if (error == MediaPlayer::NetworkError)
1978         m_error = MediaError::create(MediaError::MEDIA_ERR_NETWORK);
1979     else if (error == MediaPlayer::DecodeError)
1980         m_error = MediaError::create(MediaError::MEDIA_ERR_DECODE);
1981     else
1982         ASSERT_NOT_REACHED();
1983
1984     // 3 - Queue a task to fire a simple event named error at the media element.
1985     scheduleEvent(eventNames().errorEvent);
1986
1987 #if ENABLE(MEDIA_SOURCE)
1988     closeMediaSource();
1989 #endif
1990
1991     // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
1992     // task to fire a simple event called emptied at the element.
1993     m_networkState = NETWORK_EMPTY;
1994     scheduleEvent(eventNames().emptiedEvent);
1995
1996     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1997     setShouldDelayLoadEvent(false);
1998
1999     // 6 - Abort the overall resource selection algorithm.
2000     m_currentSourceNode = nullptr;
2001
2002 #if PLATFORM(COCOA)
2003     if (is<MediaDocument>(document()))
2004         downcast<MediaDocument>(document()).mediaElementSawUnsupportedTracks();
2005 #endif
2006 }
2007
2008 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
2009 {
2010     LOG(Media, "HTMLMediaElement::cancelPendingEventsAndCallbacks(%p)", this);
2011     m_asyncEventQueue.cancelAllEvents();
2012
2013     for (auto& source : childrenOfType<HTMLSourceElement>(*this))
2014         source.cancelPendingErrorEvent();
2015
2016     rejectPendingPlayPromises(DOMError::create("AbortError", "The operation was aborted."));
2017 }
2018
2019 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
2020 {
2021     beginProcessingMediaPlayerCallback();
2022     setNetworkState(m_player->networkState());
2023     endProcessingMediaPlayerCallback();
2024 }
2025
2026 static void logMediaLoadRequest(Page* page, const String& mediaEngine, const String& errorMessage, bool succeeded)
2027 {
2028     if (!page)
2029         return;
2030
2031     DiagnosticLoggingClient& diagnosticLoggingClient = page->diagnosticLoggingClient();
2032     if (!succeeded) {
2033         diagnosticLoggingClient.logDiagnosticMessageWithResult(DiagnosticLoggingKeys::mediaLoadingFailedKey(), errorMessage, DiagnosticLoggingResultFail, ShouldSample::No);
2034         return;
2035     }
2036
2037     diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::mediaLoadedKey(), mediaEngine, ShouldSample::No);
2038
2039     if (!page->hasSeenAnyMediaEngine())
2040         diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsAtLeastOneMediaEngineKey(), emptyString(), ShouldSample::No);
2041
2042     if (!page->hasSeenMediaEngine(mediaEngine))
2043         diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::pageContainsMediaEngineKey(), mediaEngine, ShouldSample::No);
2044
2045     page->sawMediaEngine(mediaEngine);
2046 }
2047
2048 static String stringForNetworkState(MediaPlayer::NetworkState state)
2049 {
2050     switch (state) {
2051     case MediaPlayer::Empty: return ASCIILiteral("Empty");
2052     case MediaPlayer::Idle: return ASCIILiteral("Idle");
2053     case MediaPlayer::Loading: return ASCIILiteral("Loading");
2054     case MediaPlayer::Loaded: return ASCIILiteral("Loaded");
2055     case MediaPlayer::FormatError: return ASCIILiteral("FormatError");
2056     case MediaPlayer::NetworkError: return ASCIILiteral("NetworkError");
2057     case MediaPlayer::DecodeError: return ASCIILiteral("DecodeError");
2058     default: return emptyString();
2059     }
2060 }
2061
2062 void HTMLMediaElement::mediaLoadingFailed(MediaPlayer::NetworkState error)
2063 {
2064     stopPeriodicTimers();
2065     
2066     // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
2067     // <source> children, schedule the next one
2068     if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
2069         
2070         // resource selection algorithm
2071         // 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.
2072         if (m_currentSourceNode)
2073             m_currentSourceNode->scheduleErrorEvent();
2074         else
2075             LOG(Media, "HTMLMediaElement::setNetworkState(%p) - error event not sent, <source> was removed", this);
2076         
2077         // 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.
2078         
2079         // 9.Otherwise.11 - Forget the media element's media-resource-specific tracks.
2080         forgetResourceSpecificTracks();
2081
2082         if (havePotentialSourceChild()) {
2083             LOG(Media, "HTMLMediaElement::setNetworkState(%p) - scheduling next <source>", this);
2084             scheduleNextSourceChild();
2085         } else {
2086             LOG(Media, "HTMLMediaElement::setNetworkState(%p) - no more <source> elements, waiting", this);
2087             waitForSourceChange();
2088         }
2089         
2090         return;
2091     }
2092     
2093     if ((error == MediaPlayer::NetworkError && m_readyState >= HAVE_METADATA) || error == MediaPlayer::DecodeError)
2094         mediaLoadingFailedFatally(error);
2095     else if ((error == MediaPlayer::FormatError || error == MediaPlayer::NetworkError) && m_loadState == LoadingFromSrcAttr)
2096         noneSupported();
2097     
2098     updateDisplayState();
2099     if (hasMediaControls()) {
2100         mediaControls()->reset();
2101         mediaControls()->reportedError();
2102     }
2103
2104     logMediaLoadRequest(document().page(), String(), stringForNetworkState(error), false);
2105
2106     m_mediaSession->clientCharacteristicsChanged();
2107 }
2108
2109 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
2110 {
2111     LOG(Media, "HTMLMediaElement::setNetworkState(%p) - new state = %d, current state = %d", this, static_cast<int>(state), static_cast<int>(m_networkState));
2112
2113     if (state == MediaPlayer::Empty) {
2114         // Just update the cached state and leave, we can't do anything.
2115         m_networkState = NETWORK_EMPTY;
2116         return;
2117     }
2118
2119     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
2120         mediaLoadingFailed(state);
2121         return;
2122     }
2123
2124     if (state == MediaPlayer::Idle) {
2125         if (m_networkState > NETWORK_IDLE) {
2126             changeNetworkStateFromLoadingToIdle();
2127             setShouldDelayLoadEvent(false);
2128         } else {
2129             m_networkState = NETWORK_IDLE;
2130         }
2131     }
2132
2133     if (state == MediaPlayer::Loading) {
2134         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
2135             startProgressEventTimer();
2136         m_networkState = NETWORK_LOADING;
2137     }
2138
2139     if (state == MediaPlayer::Loaded) {
2140         if (m_networkState != NETWORK_IDLE)
2141             changeNetworkStateFromLoadingToIdle();
2142         m_completelyLoaded = true;
2143     }
2144
2145     if (hasMediaControls())
2146         mediaControls()->updateStatusDisplay();
2147 }
2148
2149 void HTMLMediaElement::changeNetworkStateFromLoadingToIdle()
2150 {
2151     m_progressEventTimer.stop();
2152     if (hasMediaControls() && m_player->didLoadingProgress())
2153         mediaControls()->bufferingProgressed();
2154
2155     // Schedule one last progress event so we guarantee that at least one is fired
2156     // for files that load very quickly.
2157     scheduleEvent(eventNames().progressEvent);
2158     scheduleEvent(eventNames().suspendEvent);
2159     m_networkState = NETWORK_IDLE;
2160 }
2161
2162 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
2163 {
2164     beginProcessingMediaPlayerCallback();
2165
2166     setReadyState(m_player->readyState());
2167
2168     endProcessingMediaPlayerCallback();
2169 }
2170
2171 bool HTMLMediaElement::canTransitionFromAutoplayToPlay() const
2172 {
2173     return isAutoplaying()
2174         && paused()
2175         && autoplay()
2176         && !pausedForUserInteraction()
2177         && !document().isSandboxed(SandboxAutomaticFeatures)
2178         && mediaSession().playbackPermitted(*this);
2179 }
2180
2181 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
2182 {
2183     LOG(Media, "HTMLMediaElement::setReadyState(%p) - new state = %d, current state = %d,", this, static_cast<int>(state), static_cast<int>(m_readyState));
2184
2185     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
2186     bool wasPotentiallyPlaying = potentiallyPlaying();
2187
2188     ReadyState oldState = m_readyState;
2189     ReadyState newState = static_cast<ReadyState>(state);
2190
2191 #if ENABLE(VIDEO_TRACK)
2192     bool tracksAreReady = textTracksAreReady();
2193
2194     if (newState == oldState && m_tracksAreReady == tracksAreReady)
2195         return;
2196
2197     m_tracksAreReady = tracksAreReady;
2198 #else
2199     if (newState == oldState)
2200         return;
2201     bool tracksAreReady = true;
2202 #endif
2203     
2204     if (tracksAreReady)
2205         m_readyState = newState;
2206     else {
2207         // If a media file has text tracks the readyState may not progress beyond HAVE_FUTURE_DATA until
2208         // the text tracks are ready, regardless of the state of the media file.
2209         if (newState <= HAVE_METADATA)
2210             m_readyState = newState;
2211         else
2212             m_readyState = HAVE_CURRENT_DATA;
2213     }
2214     
2215     if (oldState > m_readyStateMaximum)
2216         m_readyStateMaximum = oldState;
2217
2218     if (m_networkState == NETWORK_EMPTY)
2219         return;
2220
2221     if (m_seeking) {
2222         // 4.8.10.9, step 11
2223         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
2224             scheduleEvent(eventNames().waitingEvent);
2225
2226         // 4.8.10.10 step 14 & 15.
2227         if (!m_player->seeking() && m_readyState >= HAVE_CURRENT_DATA)
2228             finishSeek();
2229     } else {
2230         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
2231             // 4.8.10.8
2232             invalidateCachedTime();
2233             scheduleTimeupdateEvent(false);
2234             scheduleEvent(eventNames().waitingEvent);
2235         }
2236     }
2237
2238     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
2239         prepareMediaFragmentURI();
2240         scheduleEvent(eventNames().durationchangeEvent);
2241         scheduleResizeEvent();
2242         scheduleEvent(eventNames().loadedmetadataEvent);
2243 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
2244         if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent))
2245             enqueuePlaybackTargetAvailabilityChangedEvent();
2246 #endif
2247         m_initiallyMuted = m_volume < 0.05 || muted();
2248
2249         if (hasMediaControls())
2250             mediaControls()->loadedMetadata();
2251         if (renderer())
2252             renderer()->updateFromElement();
2253
2254         if (is<MediaDocument>(document()))
2255             downcast<MediaDocument>(document()).mediaElementNaturalSizeChanged(expandedIntSize(m_player->naturalSize()));
2256
2257         logMediaLoadRequest(document().page(), m_player->engineDescription(), String(), true);
2258
2259 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
2260         updateMediaState(UpdateMediaState::Asynchronously);
2261 #endif
2262
2263         m_mediaSession->clientCharacteristicsChanged();
2264     }
2265
2266     bool shouldUpdateDisplayState = false;
2267
2268     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
2269         m_haveFiredLoadedData = true;
2270         shouldUpdateDisplayState = true;
2271         scheduleEvent(eventNames().loadeddataEvent);
2272         setShouldDelayLoadEvent(false);
2273         applyMediaFragmentURI();
2274     }
2275
2276     bool isPotentiallyPlaying = potentiallyPlaying();
2277     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) {
2278         scheduleEvent(eventNames().canplayEvent);
2279         if (isPotentiallyPlaying)
2280             scheduleNotifyAboutPlaying();
2281         shouldUpdateDisplayState = true;
2282     }
2283
2284     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && tracksAreReady) {
2285         if (oldState <= HAVE_CURRENT_DATA)
2286             scheduleEvent(eventNames().canplayEvent);
2287
2288         scheduleEvent(eventNames().canplaythroughEvent);
2289
2290         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
2291             scheduleNotifyAboutPlaying();
2292
2293         if (canTransitionFromAutoplayToPlay()) {
2294             m_paused = false;
2295             invalidateCachedTime();
2296             scheduleEvent(eventNames().playEvent);
2297             scheduleNotifyAboutPlaying();
2298         }
2299
2300         shouldUpdateDisplayState = true;
2301     }
2302
2303     if (shouldUpdateDisplayState) {
2304         updateDisplayState();
2305         if (hasMediaControls()) {
2306             mediaControls()->refreshClosedCaptionsButtonVisibility();
2307             mediaControls()->updateStatusDisplay();
2308         }
2309     }
2310
2311     updatePlayState();
2312     updateMediaController();
2313 #if ENABLE(VIDEO_TRACK)
2314     updateActiveTextTrackCues(currentMediaTime());
2315 #endif
2316 }
2317
2318 #if ENABLE(ENCRYPTED_MEDIA)
2319 void HTMLMediaElement::mediaPlayerKeyAdded(MediaPlayer*, const String& keySystem, const String& sessionId)
2320 {
2321     Ref<Event> event = MediaKeyEvent::create(eventNames().webkitkeyaddedEvent, keySystem, sessionId, nullptr, nullptr, emptyString(), nullptr, 0);
2322     event->setTarget(this);
2323     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2324 }
2325
2326 void HTMLMediaElement::mediaPlayerKeyError(MediaPlayer*, const String& keySystem, const String& sessionId, MediaPlayerClient::MediaKeyErrorCode errorCode, unsigned short systemCode)
2327 {
2328     MediaKeyError::Code mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
2329     switch (errorCode) {
2330     case MediaPlayerClient::UnknownError:
2331         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
2332         break;
2333     case MediaPlayerClient::ClientError:
2334         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_CLIENT;
2335         break;
2336     case MediaPlayerClient::ServiceError:
2337         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_SERVICE;
2338         break;
2339     case MediaPlayerClient::OutputError:
2340         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_OUTPUT;
2341         break;
2342     case MediaPlayerClient::HardwareChangeError:
2343         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_HARDWARECHANGE;
2344         break;
2345     case MediaPlayerClient::DomainError:
2346         mediaKeyErrorCode = MediaKeyError::MEDIA_KEYERR_DOMAIN;
2347         break;
2348     }
2349
2350     Ref<Event> event = MediaKeyEvent::create(eventNames().webkitkeyerrorEvent, keySystem, sessionId, nullptr, nullptr, emptyString(), MediaKeyError::create(mediaKeyErrorCode), systemCode);
2351     event->setTarget(this);
2352     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2353 }
2354
2355 void HTMLMediaElement::mediaPlayerKeyMessage(MediaPlayer*, const String& keySystem, const String& sessionId, const unsigned char* message, unsigned messageLength, const URL& defaultURL)
2356 {
2357     Ref<Event> event = MediaKeyEvent::create(eventNames().webkitkeymessageEvent, keySystem, sessionId, nullptr, Uint8Array::create(message, messageLength), defaultURL, nullptr, 0);
2358     event->setTarget(this);
2359     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2360 }
2361
2362 bool HTMLMediaElement::mediaPlayerKeyNeeded(MediaPlayer*, const String& keySystem, const String& sessionId, const unsigned char* initData, unsigned initDataLength)
2363 {
2364     if (!hasEventListeners(eventNames().webkitneedkeyEvent)) {
2365         m_error = MediaError::create(MediaError::MEDIA_ERR_ENCRYPTED);
2366         scheduleEvent(eventNames().errorEvent);
2367         return false;
2368     }
2369
2370     Ref<Event> event = MediaKeyEvent::create(eventNames().webkitneedkeyEvent, keySystem, sessionId, Uint8Array::create(initData, initDataLength), nullptr, emptyString(), nullptr, 0);
2371     event->setTarget(this);
2372     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2373     return true;
2374 }
2375 #endif
2376
2377 #if ENABLE(ENCRYPTED_MEDIA_V2)
2378 RefPtr<ArrayBuffer> HTMLMediaElement::mediaPlayerCachedKeyForKeyId(const String& keyId) const
2379 {
2380     return m_mediaKeys ? m_mediaKeys->cachedKeyForKeyId(keyId) : nullptr;
2381 }
2382
2383 bool HTMLMediaElement::mediaPlayerKeyNeeded(MediaPlayer*, Uint8Array* initData)
2384 {
2385     if (!hasEventListeners("webkitneedkey")) {
2386         m_error = MediaError::create(MediaError::MEDIA_ERR_ENCRYPTED);
2387         scheduleEvent(eventNames().errorEvent);
2388         return false;
2389     }
2390
2391     auto event = MediaKeyNeededEvent::create(eventNames().webkitneedkeyEvent, initData);
2392     event->setTarget(this);
2393     m_asyncEventQueue.enqueueEvent(WTFMove(event));
2394
2395     return true;
2396 }
2397
2398 String HTMLMediaElement::mediaPlayerMediaKeysStorageDirectory() const
2399 {
2400     Settings* settings = document().settings();
2401     if (!settings)
2402         return emptyString();
2403
2404     String storageDirectory = settings->mediaKeysStorageDirectory();
2405     if (storageDirectory.isEmpty())
2406         return emptyString();
2407
2408     SecurityOrigin* origin = document().securityOrigin();
2409     if (!origin)
2410         return emptyString();
2411
2412     return pathByAppendingComponent(storageDirectory, origin->databaseIdentifier());
2413 }
2414
2415 void HTMLMediaElement::setMediaKeys(MediaKeys* mediaKeys)
2416 {
2417     if (m_mediaKeys == mediaKeys)
2418         return;
2419
2420     if (m_mediaKeys)
2421         m_mediaKeys->setMediaElement(0);
2422     m_mediaKeys = mediaKeys;
2423     if (m_mediaKeys)
2424         m_mediaKeys->setMediaElement(this);
2425 }
2426
2427 void HTMLMediaElement::keyAdded()
2428 {
2429     if (m_player)
2430         m_player->keyAdded();
2431 }
2432 #endif
2433
2434 void HTMLMediaElement::progressEventTimerFired()
2435 {
2436     ASSERT(m_player);
2437     if (m_networkState != NETWORK_LOADING)
2438         return;
2439
2440     double time = monotonicallyIncreasingTime();
2441     double timedelta = time - m_previousProgressTime;
2442
2443     if (m_player->didLoadingProgress()) {
2444         scheduleEvent(eventNames().progressEvent);
2445         m_previousProgressTime = time;
2446         m_sentStalledEvent = false;
2447         if (renderer())
2448             renderer()->updateFromElement();
2449         if (hasMediaControls())
2450             mediaControls()->bufferingProgressed();
2451     } else if (timedelta > 3.0 && !m_sentStalledEvent) {
2452         scheduleEvent(eventNames().stalledEvent);
2453         m_sentStalledEvent = true;
2454         setShouldDelayLoadEvent(false);
2455     }
2456 }
2457
2458 void HTMLMediaElement::rewind(double timeDelta)
2459 {
2460     LOG(Media, "HTMLMediaElement::rewind(%p) - %f", this, timeDelta);
2461     setCurrentTime(std::max(currentMediaTime() - MediaTime::createWithDouble(timeDelta), minTimeSeekable()));
2462 }
2463
2464 void HTMLMediaElement::returnToRealtime()
2465 {
2466     LOG(Media, "HTMLMediaElement::returnToRealtime(%p)", this);
2467     setCurrentTime(maxTimeSeekable());
2468 }
2469
2470 void HTMLMediaElement::addPlayedRange(const MediaTime& start, const MediaTime& end)
2471 {
2472     LOG(Media, "HTMLMediaElement::addPlayedRange(%p) - [%s, %s]", this, toString(start).utf8().data(), toString(end).utf8().data());
2473     if (!m_playedTimeRanges)
2474         m_playedTimeRanges = TimeRanges::create();
2475     m_playedTimeRanges->ranges().add(start, end);
2476 }  
2477
2478 bool HTMLMediaElement::supportsScanning() const
2479 {
2480     return m_player ? m_player->supportsScanning() : false;
2481 }
2482
2483 void HTMLMediaElement::prepareToPlay()
2484 {
2485     LOG(Media, "HTMLMediaElement::prepareToPlay(%p)", this);
2486     if (m_havePreparedToPlay)
2487         return;
2488     m_havePreparedToPlay = true;
2489     m_player->prepareToPlay();
2490 }
2491
2492 void HTMLMediaElement::fastSeek(double time)
2493 {
2494     fastSeek(MediaTime::createWithDouble(time));
2495 }
2496
2497 void HTMLMediaElement::fastSeek(const MediaTime& time)
2498 {
2499     LOG(Media, "HTMLMediaElement::fastSeek(%p) - %s", this, toString(time).utf8().data());
2500     // 4.7.10.9 Seeking
2501     // 9. If the approximate-for-speed flag is set, adjust the new playback position to a value that will
2502     // allow for playback to resume promptly. If new playback position before this step is before current
2503     // playback position, then the adjusted new playback position must also be before the current playback
2504     // position. Similarly, if the new playback position before this step is after current playback position,
2505     // then the adjusted new playback position must also be after the current playback position.
2506     refreshCachedTime();
2507     MediaTime delta = time - currentMediaTime();
2508     MediaTime negativeTolerance = delta >= MediaTime::zeroTime() ? delta : MediaTime::positiveInfiniteTime();
2509     MediaTime positiveTolerance = delta < MediaTime::zeroTime() ? -delta : MediaTime::positiveInfiniteTime();
2510
2511     seekWithTolerance(time, negativeTolerance, positiveTolerance, true);
2512 }
2513
2514 void HTMLMediaElement::seek(const MediaTime& time)
2515 {
2516     LOG(Media, "HTMLMediaElement::seek(%p) - %s", this, toString(time).utf8().data());
2517     seekWithTolerance(time, MediaTime::zeroTime(), MediaTime::zeroTime(), true);
2518 }
2519
2520 void HTMLMediaElement::seekInternal(const MediaTime& time)
2521 {
2522     LOG(Media, "HTMLMediaElement::seekInternal(%p) - %s", this, toString(time).utf8().data());
2523     seekWithTolerance(time, MediaTime::zeroTime(), MediaTime::zeroTime(), false);
2524 }
2525
2526 void HTMLMediaElement::seekWithTolerance(const MediaTime& inTime, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance, bool fromDOM)
2527 {
2528     // 4.8.10.9 Seeking
2529     MediaTime time = inTime;
2530
2531     // 1 - Set the media element's show poster flag to false.
2532     setDisplayMode(Video);
2533
2534     // 2 - If the media element's readyState is HAVE_NOTHING, abort these steps.
2535     if (m_readyState == HAVE_NOTHING || !m_player)
2536         return;
2537
2538     // If the media engine has been told to postpone loading data, let it go ahead now.
2539     if (m_preload < MediaPlayer::Auto && m_readyState < HAVE_FUTURE_DATA)
2540         prepareToPlay();
2541
2542     // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
2543     refreshCachedTime();
2544     MediaTime now = currentMediaTime();
2545
2546     // 3 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
2547     // already running. Abort that other instance of the algorithm without waiting for the step that
2548     // it is running to complete.
2549     if (m_seekTaskQueue.hasPendingTasks()) {
2550         LOG(Media, "HTMLMediaElement::seekWithTolerance(%p) - cancelling pending seeks", this);
2551         m_seekTaskQueue.cancelAllTasks();
2552         if (m_pendingSeek) {
2553             now = m_pendingSeek->now;
2554             m_pendingSeek = nullptr;
2555         }
2556         m_pendingSeekType = NoSeek;
2557     }
2558
2559     // 4 - Set the seeking IDL attribute to true.
2560     // The flag will be cleared when the engine tells us the time has actually changed.
2561     m_seeking = true;
2562     if (m_playing) {
2563         if (m_lastSeekTime < now)
2564             addPlayedRange(m_lastSeekTime, now);
2565     }
2566     m_lastSeekTime = time;
2567
2568     // 5 - If the seek was in response to a DOM method call or setting of an IDL attribute, then continue
2569     // the script. The remainder of these steps must be run asynchronously.
2570     m_pendingSeek = std::make_unique<PendingSeek>(now, time, negativeTolerance, positiveTolerance);
2571     if (fromDOM) {
2572         LOG(Media, "HTMLMediaElement::seekWithTolerance(%p) - enqueuing seek from %s to %s", this, toString(now).utf8().data(), toString(time).utf8().data());
2573         m_seekTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::seekTask, this));
2574     } else
2575         seekTask();
2576 }
2577
2578 void HTMLMediaElement::seekTask()
2579 {
2580     LOG(Media, "HTMLMediaElement::seekTask(%p)", this);
2581
2582     if (!m_player) {
2583         clearSeeking();
2584         return;
2585     }
2586
2587     ASSERT(m_pendingSeek);
2588     MediaTime now = m_pendingSeek->now;
2589     MediaTime time = m_pendingSeek->targetTime;
2590     MediaTime negativeTolerance = m_pendingSeek->negativeTolerance;
2591     MediaTime positiveTolerance = m_pendingSeek->positiveTolerance;
2592     m_pendingSeek = nullptr;
2593
2594     // 6 - If the new playback position is later than the end of the media resource, then let it be the end 
2595     // of the media resource instead.
2596     time = std::min(time, durationMediaTime());
2597
2598     // 7 - If the new playback position is less than the earliest possible position, let it be that position instead.
2599     MediaTime earliestTime = m_player->startTime();
2600     time = std::max(time, earliestTime);
2601
2602     // Ask the media engine for the time value in the movie's time scale before comparing with current time. This
2603     // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's
2604     // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
2605     // not generate a timechanged callback. This means m_seeking will never be cleared and we will never 
2606     // fire a 'seeked' event.
2607 #if !LOG_DISABLED
2608     MediaTime mediaTime = m_player->mediaTimeForTimeValue(time);
2609     if (time != mediaTime)
2610         LOG(Media, "HTMLMediaElement::seekTask(%p) - %s - media timeline equivalent is %s", this, toString(time).utf8().data(), toString(mediaTime).utf8().data());
2611 #endif
2612     time = m_player->mediaTimeForTimeValue(time);
2613
2614     // 8 - If the (possibly now changed) new playback position is not in one of the ranges given in the
2615     // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute 
2616     // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
2617     // attribute then set the seeking IDL attribute to false and abort these steps.
2618     RefPtr<TimeRanges> seekableRanges = seekable();
2619     bool noSeekRequired = !seekableRanges->length();
2620
2621     // Short circuit seeking to the current time by just firing the events if no seek is required.
2622     // Don't skip calling the media engine if 1) we are in poster mode (because a seek should always cancel
2623     // poster display), or 2) if there is a pending fast seek, or 3) if this seek is not an exact seek
2624     SeekType thisSeekType = (negativeTolerance == MediaTime::zeroTime() && positiveTolerance == MediaTime::zeroTime()) ? Precise : Fast;
2625     if (!noSeekRequired && time == now && thisSeekType == Precise && m_pendingSeekType != Fast && displayMode() != Poster)
2626         noSeekRequired = true;
2627
2628 #if ENABLE(MEDIA_SOURCE)
2629     // Always notify the media engine of a seek if the source is not closed. This ensures that the source is
2630     // always in a flushed state when the 'seeking' event fires.
2631     if (m_mediaSource && !m_mediaSource->isClosed())
2632         noSeekRequired = false;
2633 #endif
2634
2635     if (noSeekRequired) {
2636         LOG(Media, "HTMLMediaElement::seekTask(%p) - seek to %s ignored", this, toString(time).utf8().data());
2637         if (time == now) {
2638             scheduleEvent(eventNames().seekingEvent);
2639             scheduleTimeupdateEvent(false);
2640             scheduleEvent(eventNames().seekedEvent);
2641         }
2642         clearSeeking();
2643         return;
2644     }
2645     time = seekableRanges->ranges().nearest(time);
2646
2647     m_sentEndEvent = false;
2648     m_lastSeekTime = time;
2649     m_pendingSeekType = thisSeekType;
2650     m_seeking = true;
2651
2652     // 10 - Queue a task to fire a simple event named seeking at the element.
2653     scheduleEvent(eventNames().seekingEvent);
2654
2655     // 11 - Set the current playback position to the given new playback position
2656     m_player->seekWithTolerance(time, negativeTolerance, positiveTolerance);
2657
2658     // 12 - Wait until the user agent has established whether or not the media data for the new playback
2659     // position is available, and, if it is, until it has decoded enough data to play back that position.
2660     // 13 - Await a stable state. The synchronous section consists of all the remaining steps of this algorithm.
2661 }
2662
2663 void HTMLMediaElement::clearSeeking()
2664 {
2665     m_seeking = false;
2666     m_pendingSeekType = NoSeek;
2667     invalidateCachedTime();
2668 }
2669
2670 void HTMLMediaElement::finishSeek()
2671 {
2672     // 4.8.10.9 Seeking
2673     // 14 - Set the seeking IDL attribute to false.
2674     clearSeeking();
2675
2676     LOG(Media, "HTMLMediaElement::finishSeek(%p) - current time = %s", this, toString(currentMediaTime()).utf8().data());
2677
2678     // 15 - Run the time maches on steps.
2679     // Handled by mediaPlayerTimeChanged().
2680
2681     // 16 - Queue a task to fire a simple event named timeupdate at the element.
2682     scheduleEvent(eventNames().timeupdateEvent);
2683
2684     // 17 - Queue a task to fire a simple event named seeked at the element.
2685     scheduleEvent(eventNames().seekedEvent);
2686
2687 #if ENABLE(MEDIA_SOURCE)
2688     if (m_mediaSource)
2689         m_mediaSource->monitorSourceBuffers();
2690 #endif
2691 }
2692
2693 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
2694 {
2695     return m_readyState;
2696 }
2697
2698 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
2699 {
2700     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
2701 }
2702
2703 bool HTMLMediaElement::hasAudio() const
2704 {
2705     return m_player ? m_player->hasAudio() : false;
2706 }
2707
2708 bool HTMLMediaElement::seeking() const
2709 {
2710     return m_seeking;
2711 }
2712
2713 void HTMLMediaElement::refreshCachedTime() const
2714 {
2715     if (!m_player)
2716         return;
2717
2718     m_cachedTime = m_player->currentTime();
2719     if (!m_cachedTime) {
2720         // Do not use m_cachedTime until the media engine returns a non-zero value because we can't 
2721         // estimate current time until playback actually begins. 
2722         invalidateCachedTime(); 
2723         return; 
2724     } 
2725
2726     m_clockTimeAtLastCachedTimeUpdate = monotonicallyIncreasingTime();
2727 }
2728
2729 void HTMLMediaElement::invalidateCachedTime() const
2730 {
2731     m_cachedTime = MediaTime::invalidTime();
2732     if (!m_player || !m_player->maximumDurationToCacheMediaTime())
2733         return;
2734
2735 #if !LOG_DISABLED
2736     if (m_cachedTime.isValid())
2737         LOG(Media, "HTMLMediaElement::invalidateCachedTime(%p)", this);
2738 #endif
2739
2740     // Don't try to cache movie time when playback first starts as the time reported by the engine
2741     // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
2742     // too early.
2743     static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
2744
2745     m_minimumClockTimeToUpdateCachedTime = monotonicallyIncreasingTime() + minimumTimePlayingBeforeCacheSnapshot;
2746 }
2747
2748 // playback state
2749 double HTMLMediaElement::currentTime() const
2750 {
2751     return currentMediaTime().toDouble();
2752 }
2753
2754 MediaTime HTMLMediaElement::currentMediaTime() const
2755 {
2756 #if LOG_CACHED_TIME_WARNINGS
2757     static const MediaTime minCachedDeltaForWarning = MediaTime::create(1, 100);
2758 #endif
2759
2760     if (!m_player)
2761         return MediaTime::zeroTime();
2762
2763     if (m_seeking) {
2764         LOG(Media, "HTMLMediaElement::currentTime(%p) - seeking, returning %s", this, toString(m_lastSeekTime).utf8().data());
2765         return m_lastSeekTime;
2766     }
2767
2768     if (m_cachedTime.isValid() && m_paused) {
2769 #if LOG_CACHED_TIME_WARNINGS
2770         MediaTime delta = m_cachedTime - m_player->currentTime();
2771         if (delta > minCachedDeltaForWarning)
2772             LOG(Media, "HTMLMediaElement::currentTime(%p) - WARNING, cached time is %s seconds off of media time when paused", this, toString(delta).utf8().data());
2773 #endif
2774         return m_cachedTime;
2775     }
2776
2777     // Is it too soon use a cached time?
2778     double now = monotonicallyIncreasingTime();
2779     double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
2780
2781     if (maximumDurationToCacheMediaTime && m_cachedTime.isValid() && !m_paused && now > m_minimumClockTimeToUpdateCachedTime) {
2782         double clockDelta = now - m_clockTimeAtLastCachedTimeUpdate;
2783
2784         // Not too soon, use the cached time only if it hasn't expired.
2785         if (clockDelta < maximumDurationToCacheMediaTime) {
2786             MediaTime adjustedCacheTime = m_cachedTime + MediaTime::createWithDouble(effectivePlaybackRate() * clockDelta);
2787
2788 #if LOG_CACHED_TIME_WARNINGS
2789             MediaTime delta = adjustedCacheTime - m_player->currentTime();
2790             if (delta > minCachedDeltaForWarning)
2791                 LOG(Media, "HTMLMediaElement::currentTime(%p) - WARNING, cached time is %f seconds off of media time when playing", this, delta);
2792 #endif
2793             return adjustedCacheTime;
2794         }
2795     }
2796
2797 #if LOG_CACHED_TIME_WARNINGS
2798     if (maximumDurationToCacheMediaTime && now > m_minimumClockTimeToUpdateCachedTime && m_cachedTime != MediaPlayer::invalidTime()) {
2799         double clockDelta = now - m_clockTimeAtLastCachedTimeUpdate;
2800         MediaTime delta = m_cachedTime + MediaTime::createWithDouble(effectivePlaybackRate() * clockDelta) - m_player->currentTime();
2801         LOG(Media, "HTMLMediaElement::currentTime(%p) - cached time was %s seconds off of media time when it expired", this, toString(delta).utf8().data());
2802     }
2803 #endif
2804
2805     refreshCachedTime();
2806
2807     if (m_cachedTime.isInvalid())
2808         return MediaTime::zeroTime();
2809     
2810     return m_cachedTime;
2811 }
2812
2813 void HTMLMediaElement::setCurrentTime(double time)
2814 {
2815     setCurrentTime(MediaTime::createWithDouble(time));
2816 }
2817
2818 void HTMLMediaElement::setCurrentTime(const MediaTime& time)
2819 {
2820     if (m_mediaController)
2821         return;
2822
2823     seekInternal(time);
2824 }
2825
2826 void HTMLMediaElement::setCurrentTime(double time, ExceptionCode& ec)
2827 {
2828     // On setting, if the media element has a current media controller, then the user agent must
2829     // throw an InvalidStateError exception
2830     if (m_mediaController) {
2831         ec = INVALID_STATE_ERR;
2832         return;
2833     }
2834
2835     seek(MediaTime::createWithDouble(time));
2836 }
2837
2838 double HTMLMediaElement::duration() const
2839 {
2840     return durationMediaTime().toDouble();
2841 }
2842
2843 MediaTime HTMLMediaElement::durationMediaTime() const
2844 {
2845     if (m_player && m_readyState >= HAVE_METADATA)
2846         return m_player->duration();
2847
2848     return MediaTime::invalidTime();
2849 }
2850
2851 bool HTMLMediaElement::paused() const
2852 {
2853     // As of this writing, JavaScript garbage collection calls this function directly. In the past
2854     // we had problems where this was called on an object after a bad cast. The assertion below
2855     // made our regression test detect the problem, so we should keep it because of that. But note
2856     // that the value of the assertion relies on the compiler not being smart enough to know that
2857     // isHTMLUnknownElement is guaranteed to return false for an HTMLMediaElement.
2858     ASSERT(!isHTMLUnknownElement());
2859
2860     return m_paused;
2861 }
2862
2863 double HTMLMediaElement::defaultPlaybackRate() const
2864 {
2865 #if ENABLE(MEDIA_STREAM)
2866     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2867     // "defaultPlaybackRate" - On setting: ignored. On getting: return 1.0
2868     // A MediaStream is not seekable. Therefore, this attribute must always have the
2869     // value 1.0 and any attempt to alter it must be ignored. Note that this also means
2870     // that the ratechange event will not fire.
2871     if (m_mediaStreamSrcObject)
2872         return 1;
2873 #endif
2874
2875     return m_defaultPlaybackRate;
2876 }
2877
2878 void HTMLMediaElement::setDefaultPlaybackRate(double rate)
2879 {
2880 #if ENABLE(MEDIA_STREAM)
2881     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2882     // "defaultPlaybackRate" - On setting: ignored. On getting: return 1.0
2883     // A MediaStream is not seekable. Therefore, this attribute must always have the
2884     // value 1.0 and any attempt to alter it must be ignored. Note that this also means
2885     // that the ratechange event will not fire.
2886     if (m_mediaStreamSrcObject)
2887         return;
2888 #endif
2889
2890     if (m_defaultPlaybackRate != rate) {
2891         LOG(Media, "HTMLMediaElement::setDefaultPlaybackRate(%p) - %f", this, rate);
2892         m_defaultPlaybackRate = rate;
2893         scheduleEvent(eventNames().ratechangeEvent);
2894     }
2895 }
2896
2897 double HTMLMediaElement::effectivePlaybackRate() const
2898 {
2899     return m_mediaController ? m_mediaController->playbackRate() : m_reportedPlaybackRate;
2900 }
2901
2902 double HTMLMediaElement::requestedPlaybackRate() const
2903 {
2904     return m_mediaController ? m_mediaController->playbackRate() : m_requestedPlaybackRate;
2905 }
2906
2907 double HTMLMediaElement::playbackRate() const
2908 {
2909 #if ENABLE(MEDIA_STREAM)
2910     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2911     // "playbackRate" - A MediaStream is not seekable. Therefore, this attribute must always
2912     // have the value 1.0 and any attempt to alter it must be ignored. Note that this also
2913     // means that the ratechange event will not fire.
2914     if (m_mediaStreamSrcObject)
2915         return 1;
2916 #endif
2917
2918     return m_requestedPlaybackRate;
2919 }
2920
2921 void HTMLMediaElement::setPlaybackRate(double rate)
2922 {
2923     LOG(Media, "HTMLMediaElement::setPlaybackRate(%p) - %f", this, rate);
2924
2925 #if ENABLE(MEDIA_STREAM)
2926     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2927     // "playbackRate" - A MediaStream is not seekable. Therefore, this attribute must always
2928     // have the value 1.0 and any attempt to alter it must be ignored. Note that this also
2929     // means that the ratechange event will not fire.
2930     if (m_mediaStreamSrcObject)
2931         return;
2932 #endif
2933
2934     if (m_player && potentiallyPlaying() && m_player->rate() != rate && !m_mediaController)
2935         m_player->setRate(rate);
2936
2937     if (m_requestedPlaybackRate != rate) {
2938         m_reportedPlaybackRate = m_requestedPlaybackRate = rate;
2939         invalidateCachedTime();
2940         scheduleEvent(eventNames().ratechangeEvent);
2941     }
2942 }
2943
2944 void HTMLMediaElement::updatePlaybackRate()
2945 {
2946     double requestedRate = requestedPlaybackRate();
2947     if (m_player && potentiallyPlaying() && m_player->rate() != requestedRate)
2948         m_player->setRate(requestedRate);
2949 }
2950
2951 bool HTMLMediaElement::webkitPreservesPitch() const
2952 {
2953     return m_webkitPreservesPitch;
2954 }
2955
2956 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
2957 {
2958     LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%p) - %s", this, boolString(preservesPitch));
2959
2960     m_webkitPreservesPitch = preservesPitch;
2961     
2962     if (!m_player)
2963         return;
2964
2965     m_player->setPreservesPitch(preservesPitch);
2966 }
2967
2968 bool HTMLMediaElement::ended() const
2969 {
2970 #if ENABLE(MEDIA_STREAM)
2971     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2972     // When the MediaStream state moves from the active to the inactive state, the User Agent
2973     // must raise an ended event on the HTMLMediaElement and set its ended attribute to true.
2974     if (m_mediaStreamSrcObject && m_player && m_player->ended())
2975         return true;
2976 #endif
2977
2978     // 4.8.10.8 Playing the media resource
2979     // The ended attribute must return true if the media element has ended 
2980     // playback and the direction of playback is forwards, and false otherwise.
2981     return endedPlayback() && requestedPlaybackRate() > 0;
2982 }
2983
2984 bool HTMLMediaElement::autoplay() const
2985 {
2986     return fastHasAttribute(autoplayAttr);
2987 }
2988
2989 String HTMLMediaElement::preload() const
2990 {
2991 #if ENABLE(MEDIA_STREAM)
2992     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
2993     // "preload" - On getting: none. On setting: ignored.
2994     if (m_mediaStreamSrcObject)
2995         return ASCIILiteral("none");
2996 #endif
2997
2998     switch (m_preload) {
2999     case MediaPlayer::None:
3000         return ASCIILiteral("none");
3001     case MediaPlayer::MetaData:
3002         return ASCIILiteral("metadata");
3003     case MediaPlayer::Auto:
3004         return ASCIILiteral("auto");
3005     }
3006
3007     ASSERT_NOT_REACHED();
3008     return String();
3009 }
3010
3011 void HTMLMediaElement::setPreload(const String& preload)
3012 {
3013     LOG(Media, "HTMLMediaElement::setPreload(%p) - %s", this, preload.utf8().data());
3014 #if ENABLE(MEDIA_STREAM)
3015     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
3016     // "preload" - On getting: none. On setting: ignored.
3017     if (m_mediaStreamSrcObject)
3018         return;
3019 #endif
3020
3021     setAttribute(preloadAttr, preload);
3022 }
3023
3024 void HTMLMediaElement::play(PlayPromise&& promise)
3025 {
3026     LOG(Media, "HTMLMediaElement::play(%p)", this);
3027
3028     if (!m_mediaSession->playbackPermitted(*this)) {
3029         promise.reject(DOMError::create("NotAllowedError", "The request is not allowed by the user agent or the platform in the current context."));
3030         return;
3031     }
3032
3033     if (m_error && m_error->code() == MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED) {
3034         promise.reject(DOMError::create("NotSupportedError", "The operation is not supported.."));
3035         return;
3036     }
3037
3038     if (ScriptController::processingUserGestureForMedia())
3039         removeBehaviorsRestrictionsAfterFirstUserGesture();
3040
3041     if (!playInternal())
3042         promise.reject(DOMError::create("NotAllowedError", "The request is not allowed by the user agent or the platform in the current context."));
3043
3044     m_pendingPlayPromises.append(WTFMove(promise));
3045 }
3046
3047 void HTMLMediaElement::play()
3048 {
3049     LOG(Media, "HTMLMediaElement::play(%p)", this);
3050
3051     if (!m_mediaSession->playbackPermitted(*this))
3052         return;
3053     if (ScriptController::processingUserGestureForMedia())
3054         removeBehaviorsRestrictionsAfterFirstUserGesture();
3055
3056     playInternal();
3057 }
3058
3059 bool HTMLMediaElement::playInternal()
3060 {
3061     LOG(Media, "HTMLMediaElement::playInternal(%p)", this);
3062     
3063     if (!m_mediaSession->clientWillBeginPlayback()) {
3064         LOG(Media, "  returning because of interruption");
3065         return false;
3066     }
3067
3068     // 4.8.10.9. Playing the media resource
3069     if (!m_player || m_networkState == NETWORK_EMPTY)
3070         scheduleDelayedAction(LoadMediaResource);
3071
3072     if (endedPlayback())
3073         seekInternal(MediaTime::zeroTime());
3074
3075     if (m_mediaController)
3076         m_mediaController->bringElementUpToSpeed(this);
3077
3078     if (m_paused) {
3079         m_paused = false;
3080         invalidateCachedTime();
3081         scheduleEvent(eventNames().playEvent);
3082
3083         if (m_readyState <= HAVE_CURRENT_DATA)
3084             scheduleEvent(eventNames().waitingEvent);
3085         else if (m_readyState >= HAVE_FUTURE_DATA)
3086             scheduleNotifyAboutPlaying();
3087
3088 #if ENABLE(MEDIA_SESSION)
3089         // 6.3 Activating a media session from a media element
3090         // When the play() method is invoked, the paused attribute is true, and the readyState attribute has the value
3091         // HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA, then
3092         // 1. Let media session be the value of the current media session.
3093         // 2. If we are not currently in media session's list of active participating media elements then append
3094         //    ourselves to this list.
3095         // 3. Let activated be the result of running the media session invocation algorithm for media session.
3096         // 4. If activated is failure, pause ourselves.
3097         if (m_readyState == HAVE_ENOUGH_DATA || m_readyState == HAVE_FUTURE_DATA) {
3098             if (m_session) {
3099                 m_session->addActiveMediaElement(*this);
3100
3101                 if (m_session->kind() == MediaSessionKind::Content) {
3102                     if (Page* page = document().page())
3103                         page->chrome().client().focusedContentMediaElementDidChange(m_elementID);
3104                 }
3105
3106                 if (!m_session->invoke()) {
3107                     pause();
3108                     return false;
3109                 }
3110             }
3111         }
3112 #endif
3113     } else if (m_readyState >= HAVE_FUTURE_DATA)
3114         scheduleResolvePendingPlayPromises();
3115
3116     m_autoplaying = false;
3117     updatePlayState();
3118     updateMediaController();
3119     return true;
3120 }
3121
3122 void HTMLMediaElement::pause()
3123 {
3124     LOG(Media, "HTMLMediaElement::pause(%p)", this);
3125
3126     if (!m_mediaSession->playbackPermitted(*this))
3127         return;
3128
3129     pauseInternal();
3130 }
3131
3132
3133 void HTMLMediaElement::pauseInternal()
3134 {
3135     LOG(Media, "HTMLMediaElement::pauseInternal(%p)", this);
3136
3137     if (!m_mediaSession->clientWillPausePlayback()) {
3138         LOG(Media, "  returning because of interruption");
3139         return;
3140     }
3141
3142     // 4.8.10.9. Playing the media resource
3143     if (!m_player || m_networkState == NETWORK_EMPTY) {
3144         // Unless the restriction on media requiring user action has been lifted
3145         // don't trigger loading if a script calls pause().
3146         if (!m_mediaSession->playbackPermitted(*this))
3147             return;
3148         scheduleDelayedAction(LoadMediaResource);
3149     }
3150
3151     m_autoplaying = false;
3152
3153     if (!m_paused) {
3154         m_paused = true;
3155         scheduleTimeupdateEvent(false);
3156         scheduleEvent(eventNames().pauseEvent);
3157         rejectPendingPlayPromises(DOMError::create("AbortError", "The operation was aborted."));
3158
3159         if (MemoryPressureHandler::singleton().isUnderMemoryPressure())
3160             purgeBufferedDataIfPossible();
3161     }
3162
3163     updatePlayState();
3164 }
3165
3166 #if ENABLE(MEDIA_SOURCE)
3167 void HTMLMediaElement::closeMediaSource()
3168 {
3169     if (!m_mediaSource)
3170         return;
3171
3172     m_mediaSource->close();
3173     m_mediaSource = nullptr;
3174 }
3175 #endif
3176
3177 #if ENABLE(ENCRYPTED_MEDIA)
3178 void HTMLMediaElement::webkitGenerateKeyRequest(const String& keySystem, const RefPtr<Uint8Array>& initData, ExceptionCode& ec)
3179 {
3180 #if ENABLE(ENCRYPTED_MEDIA_V2)
3181     static bool firstTime = true;
3182     if (firstTime && scriptExecutionContext()) {
3183         scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("'HTMLMediaElement.webkitGenerateKeyRequest()' is deprecated.  Use 'MediaKeys.createSession()' instead."));
3184         firstTime = false;
3185     }
3186 #endif
3187
3188     if (keySystem.isEmpty()) {
3189         ec = SYNTAX_ERR;
3190         return;
3191     }
3192
3193     if (!m_player) {
3194         ec = INVALID_STATE_ERR;
3195         return;
3196     }
3197
3198     const unsigned char* initDataPointer = nullptr;
3199     unsigned initDataLength = 0;
3200     if (initData) {
3201         initDataPointer = initData->data();
3202         initDataLength = initData->length();
3203     }
3204
3205     MediaPlayer::MediaKeyException result = m_player->generateKeyRequest(keySystem, initDataPointer, initDataLength);
3206     ec = exceptionCodeForMediaKeyException(result);
3207 }
3208
3209 void HTMLMediaElement::webkitAddKey(const String& keySystem, Uint8Array& key, const RefPtr<Uint8Array>& initData, const String& sessionId, ExceptionCode& ec)
3210 {
3211 #if ENABLE(ENCRYPTED_MEDIA_V2)
3212     static bool firstTime = true;
3213     if (firstTime && scriptExecutionContext()) {
3214         scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("'HTMLMediaElement.webkitAddKey()' is deprecated.  Use 'MediaKeySession.update()' instead."));
3215         firstTime = false;
3216     }
3217 #endif
3218
3219     if (keySystem.isEmpty()) {
3220         ec = SYNTAX_ERR;
3221         return;
3222     }
3223
3224     if (!key.length()) {
3225         ec = TYPE_MISMATCH_ERR;
3226         return;
3227     }
3228
3229     if (!m_player) {
3230         ec = INVALID_STATE_ERR;
3231         return;
3232     }
3233
3234     const unsigned char* initDataPointer = nullptr;
3235     unsigned initDataLength = 0;
3236     if (initData) {
3237         initDataPointer = initData->data();
3238         initDataLength = initData->length();
3239     }
3240
3241     MediaPlayer::MediaKeyException result = m_player->addKey(keySystem, key.data(), key.length(), initDataPointer, initDataLength, sessionId);
3242     ec = exceptionCodeForMediaKeyException(result);
3243 }
3244
3245 void HTMLMediaElement::webkitCancelKeyRequest(const String& keySystem, const String& sessionId, ExceptionCode& ec)
3246 {
3247     if (keySystem.isEmpty()) {
3248         ec = SYNTAX_ERR;
3249         return;
3250     }
3251
3252     if (!m_player) {
3253         ec = INVALID_STATE_ERR;
3254         return;
3255     }
3256
3257     MediaPlayer::MediaKeyException result = m_player->cancelKeyRequest(keySystem, sessionId);
3258     ec = exceptionCodeForMediaKeyException(result);
3259 }
3260
3261 #endif
3262
3263 bool HTMLMediaElement::loop() const
3264 {
3265     return fastHasAttribute(loopAttr);
3266 }
3267
3268 void HTMLMediaElement::setLoop(bool b)
3269 {
3270     LOG(Media, "HTMLMediaElement::setLoop(%p) - %s", this, boolString(b));
3271     setBooleanAttribute(loopAttr, b);
3272 }
3273
3274 bool HTMLMediaElement::controls() const
3275 {
3276     Frame* frame = document().frame();
3277
3278     // always show controls when scripting is disabled
3279     if (frame && !frame->script().canExecuteScripts(NotAboutToExecuteScript))
3280         return true;
3281
3282     return fastHasAttribute(controlsAttr);
3283 }
3284
3285 void HTMLMediaElement::setControls(bool b)
3286 {
3287     LOG(Media, "HTMLMediaElement::setControls(%p) - %s", this, boolString(b));
3288     setBooleanAttribute(controlsAttr, b);
3289 }
3290
3291 double HTMLMediaElement::volume() const
3292 {
3293     return m_volume;
3294 }
3295
3296 void HTMLMediaElement::setVolume(double vol, ExceptionCode& ec)
3297 {
3298     LOG(Media, "HTMLMediaElement::setVolume(%p) - %f", this, vol);
3299
3300     if (vol < 0.0f || vol > 1.0f) {
3301         ec = INDEX_SIZE_ERR;
3302         return;
3303     }
3304     
3305 #if !PLATFORM(IOS)
3306     if (m_volume != vol) {
3307         m_volume = vol;
3308         m_volumeInitialized = true;
3309         updateVolume();
3310         scheduleEvent(eventNames().volumechangeEvent);
3311     }
3312 #endif
3313 }
3314
3315 bool HTMLMediaElement::muted() const
3316 {
3317     return m_explicitlyMuted ? m_muted : fastHasAttribute(mutedAttr);
3318 }
3319
3320 void HTMLMediaElement::setMuted(bool muted)
3321 {
3322     LOG(Media, "HTMLMediaElement::setMuted(%p) - %s", this, boolString(muted));
3323
3324 #if PLATFORM(IOS)
3325     UNUSED_PARAM(muted);
3326 #else
3327     if (m_muted != muted || !m_explicitlyMuted) {
3328         m_muted = muted;
3329         m_explicitlyMuted = true;
3330         // Avoid recursion when the player reports volume changes.
3331         if (!processingMediaPlayerCallback()) {
3332             if (m_player) {
3333                 m_player->setMuted(effectiveMuted());
3334                 if (hasMediaControls())
3335                     mediaControls()->changedMute();
3336             }
3337         }
3338         scheduleEvent(eventNames().volumechangeEvent);
3339
3340         updateShouldPlay();
3341
3342 #if ENABLE(MEDIA_SESSION)
3343         document().updateIsPlayingMedia(m_elementID);
3344 #else
3345         document().updateIsPlayingMedia();
3346 #endif
3347
3348 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
3349         updateMediaState(UpdateMediaState::Asynchronously);
3350 #endif
3351     }
3352 #endif
3353 }
3354
3355 void HTMLMediaElement::togglePlayState()
3356 {
3357     LOG(Media, "HTMLMediaElement::togglePlayState(%p) - canPlay() is %s", this, boolString(canPlay()));
3358
3359     // We can safely call the internal play/pause methods, which don't check restrictions, because
3360     // this method is only called from the built-in media controller
3361     if (canPlay()) {
3362         updatePlaybackRate();
3363         playInternal();
3364     } else 
3365         pauseInternal();
3366 }
3367
3368 void HTMLMediaElement::beginScrubbing()
3369 {
3370     LOG(Media, "HTMLMediaElement::beginScrubbing(%p) - paused() is %s", this, boolString(paused()));
3371
3372     if (!paused()) {
3373         if (ended()) {
3374             // Because a media element stays in non-paused state when it reaches end, playback resumes 
3375             // when the slider is dragged from the end to another position unless we pause first. Do 
3376             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
3377             pause();
3378         } else {
3379             // Not at the end but we still want to pause playback so the media engine doesn't try to
3380             // continue playing during scrubbing. Pause without generating an event as we will 
3381             // unpause after scrubbing finishes.
3382             setPausedInternal(true);
3383         }
3384     }
3385 }
3386
3387 void HTMLMediaElement::endScrubbing()
3388 {
3389     LOG(Media, "HTMLMediaElement::endScrubbing(%p) - m_pausedInternal is %s", this, boolString(m_pausedInternal));
3390
3391     if (m_pausedInternal)
3392         setPausedInternal(false);
3393 }
3394
3395 void HTMLMediaElement::beginScanning(ScanDirection direction)
3396 {
3397     m_scanType = supportsScanning() ? Scan : Seek;
3398     m_scanDirection = direction;
3399
3400     if (m_scanType == Seek) {
3401         // Scanning by seeking requires the video to be paused during scanning.
3402         m_actionAfterScan = paused() ? Nothing : Play;
3403         pause();
3404     } else {
3405         // Scanning by scanning requires the video to be playing during scanninging.
3406         m_actionAfterScan = paused() ? Pause : Nothing;
3407         play();
3408         setPlaybackRate(nextScanRate());
3409     }
3410
3411     m_scanTimer.start(0, m_scanType == Seek ? SeekRepeatDelay : ScanRepeatDelay);
3412 }
3413
3414 void HTMLMediaElement::endScanning()
3415 {
3416     if (m_scanType == Scan)
3417         setPlaybackRate(defaultPlaybackRate());
3418
3419     if (m_actionAfterScan == Play)
3420         play();
3421     else if (m_actionAfterScan == Pause)
3422         pause();
3423
3424     if (m_scanTimer.isActive())
3425         m_scanTimer.stop();
3426 }
3427
3428 double HTMLMediaElement::nextScanRate()
3429 {
3430     double rate = std::min(ScanMaximumRate, fabs(playbackRate() * 2));
3431     if (m_scanDirection == Backward)
3432         rate *= -1;
3433 #if PLATFORM(IOS)
3434     rate = std::min(std::max(rate, minFastReverseRate()), maxFastForwardRate());
3435 #endif
3436     return rate;
3437 }
3438
3439 void HTMLMediaElement::scanTimerFired()
3440 {
3441     if (m_scanType == Seek) {
3442         double seekTime = m_scanDirection == Forward ? SeekTime : -SeekTime;
3443         setCurrentTime(currentTime() + seekTime);
3444     } else
3445         setPlaybackRate(nextScanRate());
3446 }
3447
3448 // The spec says to fire periodic timeupdate events (those sent while playing) every
3449 // "15 to 250ms", we choose the slowest frequency
3450 static const double maxTimeupdateEventFrequency = 0.25;
3451
3452 void HTMLMediaElement::startPlaybackProgressTimer()
3453 {
3454     if (m_playbackProgressTimer.isActive())
3455         return;
3456
3457     m_previousProgressTime = monotonicallyIncreasingTime();
3458     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
3459 }
3460
3461 void HTMLMediaElement::playbackProgressTimerFired()
3462 {
3463     ASSERT(m_player);
3464
3465     if (m_fragmentEndTime.isValid() && currentMediaTime() >= m_fragmentEndTime && requestedPlaybackRate() > 0) {
3466         m_fragmentEndTime = MediaTime::invalidTime();
3467         if (!m_mediaController && !m_paused) {
3468             // changes paused to true and fires a simple event named pause at the media element.
3469             pauseInternal();
3470         }
3471     }
3472     
3473     scheduleTimeupdateEvent(true);
3474
3475     if (!requestedPlaybackRate())
3476         return;
3477
3478     if (!m_paused && hasMediaControls())
3479         mediaControls()->playbackProgressed();
3480
3481 #if ENABLE(VIDEO_TRACK)
3482     updateActiveTextTrackCues(currentMediaTime());
3483 #endif
3484
3485 #if ENABLE(MEDIA_SOURCE)
3486     if (m_mediaSource)
3487         m_mediaSource->monitorSourceBuffers();
3488 #endif
3489 }
3490
3491 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
3492 {
3493     double now = monotonicallyIncreasingTime();
3494     double timedelta = now - m_clockTimeAtLastUpdateEvent;
3495
3496     // throttle the periodic events
3497     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
3498         return;
3499
3500     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
3501     // event at a given time so filter here
3502     MediaTime movieTime = currentMediaTime();
3503     if (movieTime != m_lastTimeUpdateEventMovieTime) {
3504         scheduleEvent(eventNames().timeupdateEvent);
3505         m_clockTimeAtLastUpdateEvent = now;
3506         m_lastTimeUpdateEventMovieTime = movieTime;
3507     }
3508 }
3509
3510 bool HTMLMediaElement::canPlay() const
3511 {
3512     return paused() || ended() || m_readyState < HAVE_METADATA;
3513 }
3514
3515 double HTMLMediaElement::percentLoaded() const
3516 {