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