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