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