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