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