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