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