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