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