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