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