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