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