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