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