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