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