2011-02-06 Maciej Stachowiak <mjs@apple.com>
[WebKit.git] / Source / WebCore / html / HTMLMediaElement.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010 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 "Attribute.h"
32 #include "Chrome.h"
33 #include "ChromeClient.h"
34 #include "ClientRect.h"
35 #include "ClientRectList.h"
36 #include "ContentType.h"
37 #include "CSSPropertyNames.h"
38 #include "CSSValueKeywords.h"
39 #include "Event.h"
40 #include "EventNames.h"
41 #include "ExceptionCode.h"
42 #include "Frame.h"
43 #include "FrameLoader.h"
44 #include "FrameLoaderClient.h"
45 #include "FrameView.h"
46 #include "HTMLDocument.h"
47 #include "HTMLNames.h"
48 #include "HTMLSourceElement.h"
49 #include "HTMLVideoElement.h"
50 #include "Logging.h"
51 #include "MediaControls.h"
52 #include "MediaDocument.h"
53 #include "MediaError.h"
54 #include "MediaList.h"
55 #include "MediaPlayer.h"
56 #include "MediaQueryEvaluator.h"
57 #include "MIMETypeRegistry.h"
58 #include "Page.h"
59 #include "RenderVideo.h"
60 #include "RenderView.h"
61 #include "ScriptEventListener.h"
62 #include "Settings.h"
63 #include "TimeRanges.h"
64 #include <limits>
65 #include <wtf/CurrentTime.h>
66 #include <wtf/MathExtras.h>
67 #include <wtf/text/CString.h>
68
69 #if USE(ACCELERATED_COMPOSITING)
70 #include "RenderView.h"
71 #include "RenderLayerCompositor.h"
72 #endif
73
74 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
75 #include "RenderEmbeddedObject.h"
76 #include "Widget.h"
77 #endif
78
79 using namespace std;
80
81 namespace WebCore {
82
83 #if !LOG_DISABLED
84 static String urlForLogging(const String& url)
85 {
86     static const unsigned maximumURLLengthForLogging = 128;
87
88     if (url.length() < maximumURLLengthForLogging)
89         return url;
90     return url.substring(0, maximumURLLengthForLogging) + "...";
91 }
92
93 static const char *boolString(bool val)
94 {
95     return val ? "true" : "false";
96 }
97 #endif
98
99 #ifndef LOG_MEDIA_EVENTS
100 // Default to not logging events because so many are generated they can overwhelm the rest of 
101 // the logging.
102 #define LOG_MEDIA_EVENTS 0
103 #endif
104
105 #ifndef LOG_CACHED_TIME_WARNINGS
106 // Default to not logging warnings about excessive drift in the cached media time because it adds a
107 // fair amount of overhead and logging.
108 #define LOG_CACHED_TIME_WARNINGS 0
109 #endif
110
111 static const float invalidMediaTime = -1;
112
113 using namespace HTMLNames;
114
115 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document)
116     : HTMLElement(tagName, document)
117     , ActiveDOMObject(document, this)
118     , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
119     , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
120     , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
121     , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
122     , m_playedTimeRanges()
123     , m_playbackRate(1.0f)
124     , m_defaultPlaybackRate(1.0f)
125     , m_webkitPreservesPitch(true)
126     , m_networkState(NETWORK_EMPTY)
127     , m_readyState(HAVE_NOTHING)
128     , m_readyStateMaximum(HAVE_NOTHING)
129     , m_volume(1.0f)
130     , m_lastSeekTime(0)
131     , m_previousProgress(0)
132     , m_previousProgressTime(numeric_limits<double>::max())
133     , m_lastTimeUpdateEventWallTime(0)
134     , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max())
135     , m_loadState(WaitingForSource)
136     , m_currentSourceNode(0)
137     , m_nextChildNodeToConsider(0)
138     , m_player(0)
139 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
140     , m_proxyWidget(0)
141 #endif
142     , m_restrictions(NoRestrictions)
143     , m_preload(MediaPlayer::Auto)
144     , m_displayMode(Unknown)
145     , m_processingMediaPlayerCallback(0)
146     , m_cachedTime(invalidMediaTime)
147     , m_cachedTimeWallClockUpdateTime(0)
148     , m_minimumWallClockTimeToCacheMediaTime(0)
149     , m_playing(false)
150     , m_isWaitingUntilMediaCanStart(false)
151     , m_shouldDelayLoadEvent(false)
152     , m_haveFiredLoadedData(false)
153     , m_inActiveDocument(true)
154     , m_autoplaying(true)
155     , m_muted(false)
156     , m_paused(true)
157     , m_seeking(false)
158     , m_sentStalledEvent(false)
159     , m_sentEndEvent(false)
160     , m_pausedInternal(false)
161     , m_sendProgressEvents(true)
162     , m_isFullscreen(false)
163     , m_closedCaptionsVisible(false)
164 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
165     , m_needWidgetUpdate(false)
166 #endif
167     , m_dispatchingCanPlayEvent(false)
168     , m_loadInitiatedByUserGesture(false)
169     , m_completelyLoaded(false)
170 {
171     LOG(Media, "HTMLMediaElement::HTMLMediaElement");
172     document->registerForDocumentActivationCallbacks(this);
173     document->registerForMediaVolumeCallbacks(this);
174 }
175
176 HTMLMediaElement::~HTMLMediaElement()
177 {
178     LOG(Media, "HTMLMediaElement::~HTMLMediaElement");
179     if (m_isWaitingUntilMediaCanStart)
180         document()->removeMediaCanStartListener(this);
181     setShouldDelayLoadEvent(false);
182     document()->unregisterForDocumentActivationCallbacks(this);
183     document()->unregisterForMediaVolumeCallbacks(this);
184 }
185
186 void HTMLMediaElement::willMoveToNewOwnerDocument()
187 {
188     if (m_isWaitingUntilMediaCanStart)
189         document()->removeMediaCanStartListener(this);
190     setShouldDelayLoadEvent(false);
191     document()->unregisterForDocumentActivationCallbacks(this);
192     document()->unregisterForMediaVolumeCallbacks(this);
193     HTMLElement::willMoveToNewOwnerDocument();
194 }
195
196 void HTMLMediaElement::didMoveToNewOwnerDocument()
197 {
198     if (m_isWaitingUntilMediaCanStart)
199         document()->addMediaCanStartListener(this);
200     if (m_readyState < HAVE_CURRENT_DATA)
201         setShouldDelayLoadEvent(true);
202     document()->registerForDocumentActivationCallbacks(this);
203     document()->registerForMediaVolumeCallbacks(this);
204     HTMLElement::didMoveToNewOwnerDocument();
205 }
206
207 void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls)
208 {
209     HTMLElement::attributeChanged(attr, preserveDecls);
210
211     const QualifiedName& attrName = attr->name();
212     if (attrName == srcAttr) {
213         // Trigger a reload, as long as the 'src' attribute is present.
214         if (!getAttribute(srcAttr).isEmpty())
215             scheduleLoad();
216     }
217     else if (attrName == controlsAttr) {
218 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
219         if (!isVideo() && attached() && (controls() != (renderer() != 0))) {
220             detach();
221             attach();
222         }
223         if (renderer())
224             renderer()->updateFromElement();
225 #else
226         if (m_player)
227             m_player->setControls(controls());
228 #endif
229     }
230 }
231
232 void HTMLMediaElement::parseMappedAttribute(Attribute* attr)
233 {
234     const QualifiedName& attrName = attr->name();
235
236     if (attrName == preloadAttr) {
237         String value = attr->value();
238
239         if (equalIgnoringCase(value, "none"))
240             m_preload = MediaPlayer::None;
241         else if (equalIgnoringCase(value, "metadata"))
242             m_preload = MediaPlayer::MetaData;
243         else {
244             // The spec does not define an "invalid value default" but "auto" is suggested as the
245             // "missing value default", so use it for everything except "none" and "metadata"
246             m_preload = MediaPlayer::Auto;
247         }
248
249         // The attribute must be ignored if the autoplay attribute is present
250         if (!autoplay() && m_player)
251             m_player->setPreload(m_preload);
252
253     } else if (attrName == onabortAttr)
254         setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
255     else if (attrName == onbeforeloadAttr)
256         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
257     else if (attrName == oncanplayAttr)
258         setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, attr));
259     else if (attrName == oncanplaythroughAttr)
260         setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, attr));
261     else if (attrName == ondurationchangeAttr)
262         setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, attr));
263     else if (attrName == onemptiedAttr)
264         setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, attr));
265     else if (attrName == onendedAttr)
266         setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, attr));
267     else if (attrName == onerrorAttr)
268         setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr));
269     else if (attrName == onloadeddataAttr)
270         setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
271     else if (attrName == onloadedmetadataAttr)
272         setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
273     else if (attrName == onloadstartAttr)
274         setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
275     else if (attrName == onpauseAttr)
276         setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, attr));
277     else if (attrName == onplayAttr)
278         setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, attr));
279     else if (attrName == onplayingAttr)
280         setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, attr));
281     else if (attrName == onprogressAttr)
282         setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, attr));
283     else if (attrName == onratechangeAttr)
284         setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, attr));
285     else if (attrName == onseekedAttr)
286         setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, attr));
287     else if (attrName == onseekingAttr)
288         setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, attr));
289     else if (attrName == onstalledAttr)
290         setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, attr));
291     else if (attrName == onsuspendAttr)
292         setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, attr));
293     else if (attrName == ontimeupdateAttr)
294         setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, attr));
295     else if (attrName == onvolumechangeAttr)
296         setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, attr));
297     else if (attrName == onwaitingAttr)
298         setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, attr));
299     else if (attrName == onwebkitbeginfullscreenAttr)
300         setAttributeEventListener(eventNames().webkitbeginfullscreenEvent, createAttributeEventListener(this, attr));
301     else if (attrName == onwebkitendfullscreenAttr)
302         setAttributeEventListener(eventNames().webkitendfullscreenEvent, createAttributeEventListener(this, attr));
303     else
304         HTMLElement::parseMappedAttribute(attr);
305 }
306
307 bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style)
308 {
309 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
310     UNUSED_PARAM(style);
311     Frame* frame = document()->frame();
312     if (!frame)
313         return false;
314
315     return true;
316 #else
317     return controls() ? HTMLElement::rendererIsNeeded(style) : false;
318 #endif
319 }
320
321 RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
322 {
323 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
324     // Setup the renderer if we already have a proxy widget.
325     RenderEmbeddedObject* mediaRenderer = new (arena) RenderEmbeddedObject(this);
326     if (m_proxyWidget) {
327         mediaRenderer->setWidget(m_proxyWidget);
328
329         Frame* frame = document()->frame();
330         FrameLoader* loader = frame ? frame->loader() : 0;
331         if (loader)
332             loader->showMediaPlayerProxyPlugin(m_proxyWidget.get());
333     }
334     return mediaRenderer;
335 #else
336     return new (arena) RenderMedia(this);
337 #endif
338 }
339  
340 void HTMLMediaElement::insertedIntoDocument()
341 {
342     LOG(Media, "HTMLMediaElement::removedFromDocument");
343     HTMLElement::insertedIntoDocument();
344     if (!getAttribute(srcAttr).isEmpty() && m_networkState == NETWORK_EMPTY)
345         scheduleLoad();
346 }
347
348 void HTMLMediaElement::removedFromDocument()
349 {
350     LOG(Media, "HTMLMediaElement::removedFromDocument");
351     if (m_networkState > NETWORK_EMPTY)
352         pause(processingUserGesture());
353     if (m_isFullscreen)
354         exitFullscreen();
355     HTMLElement::removedFromDocument();
356 }
357
358 void HTMLMediaElement::attach()
359 {
360     ASSERT(!attached());
361
362 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
363     m_needWidgetUpdate = true;
364 #endif
365
366     HTMLElement::attach();
367
368     if (renderer())
369         renderer()->updateFromElement();
370 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
371     else if (m_proxyWidget) {
372         Frame* frame = document()->frame();
373         FrameLoader* loader = frame ? frame->loader() : 0;
374         if (loader)
375             loader->hideMediaPlayerProxyPlugin(m_proxyWidget.get());
376     }
377 #endif
378 }
379
380 void HTMLMediaElement::recalcStyle(StyleChange change)
381 {
382     HTMLElement::recalcStyle(change);
383
384     if (renderer())
385         renderer()->updateFromElement();
386 }
387
388 void HTMLMediaElement::scheduleLoad()
389 {
390     LOG(Media, "HTMLMediaElement::scheduleLoad");
391 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
392     createMediaPlayerProxy();
393 #endif
394
395     if (m_loadTimer.isActive())
396         return;
397     prepareForLoad();
398     m_loadTimer.startOneShot(0);
399 }
400
401 void HTMLMediaElement::scheduleNextSourceChild()
402 {
403     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
404     m_loadTimer.startOneShot(0);
405 }
406
407 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
408 {
409 #if LOG_MEDIA_EVENTS
410     LOG(Media, "HTMLMediaElement::scheduleEvent - scheduling '%s'", eventName.string().ascii().data());
411 #endif
412     m_pendingEvents.append(Event::create(eventName, false, true));
413     if (!m_asyncEventTimer.isActive())
414         m_asyncEventTimer.startOneShot(0);
415 }
416
417 void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
418 {
419     Vector<RefPtr<Event> > pendingEvents;
420     ExceptionCode ec = 0;
421
422     m_pendingEvents.swap(pendingEvents);
423     unsigned count = pendingEvents.size();
424     for (unsigned ndx = 0; ndx < count; ++ndx) {
425 #if LOG_MEDIA_EVENTS
426         LOG(Media, "HTMLMediaElement::asyncEventTimerFired - dispatching '%s'", pendingEvents[ndx]->type().string().ascii().data());
427 #endif
428         if (pendingEvents[ndx]->type() == eventNames().canplayEvent) {
429             m_dispatchingCanPlayEvent = true;
430             dispatchEvent(pendingEvents[ndx].release(), ec);
431             m_dispatchingCanPlayEvent = false;
432         } else
433             dispatchEvent(pendingEvents[ndx].release(), ec);
434     }
435 }
436
437 void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
438 {
439     if (m_loadState == LoadingFromSourceElement)
440         loadNextSourceChild();
441     else
442         loadInternal();
443 }
444
445 PassRefPtr<MediaError> HTMLMediaElement::error() const 
446 {
447     return m_error;
448 }
449
450 void HTMLMediaElement::setSrc(const String& url)
451 {
452     setAttribute(srcAttr, url);
453 }
454
455 String HTMLMediaElement::currentSrc() const
456 {
457     return m_currentSrc;
458 }
459
460 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
461 {
462     return m_networkState;
463 }
464
465 String HTMLMediaElement::canPlayType(const String& mimeType) const
466 {
467     MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType));
468     String canPlay;
469
470     // 4.8.10.3
471     switch (support)
472     {
473         case MediaPlayer::IsNotSupported:
474             canPlay = "";
475             break;
476         case MediaPlayer::MayBeSupported:
477             canPlay = "maybe";
478             break;
479         case MediaPlayer::IsSupported:
480             canPlay = "probably";
481             break;
482     }
483     
484     LOG(Media, "HTMLMediaElement::canPlayType(%s) -> %s", mimeType.utf8().data(), canPlay.utf8().data());
485
486     return canPlay;
487 }
488
489 void HTMLMediaElement::load(bool isUserGesture, ExceptionCode& ec)
490 {
491     LOG(Media, "HTMLMediaElement::load(isUserGesture : %s)", boolString(isUserGesture));
492
493     if (m_restrictions & RequireUserGestureForLoadRestriction && !isUserGesture)
494         ec = INVALID_STATE_ERR;
495     else {
496         m_loadInitiatedByUserGesture = isUserGesture;
497         prepareForLoad();
498         loadInternal();
499     }
500 }
501
502 void HTMLMediaElement::prepareForLoad()
503 {
504     LOG(Media, "HTMLMediaElement::prepareForLoad");
505
506     // Perform the cleanup required for the resource load algorithm to run.
507     stopPeriodicTimers();
508     m_loadTimer.stop();
509     m_sentStalledEvent = false;
510     m_haveFiredLoadedData = false;
511     m_completelyLoaded = false;
512     m_displayMode = Unknown;
513
514     // 1 - Abort any already-running instance of the resource selection algorithm for this element.
515     m_loadState = WaitingForSource;
516     m_currentSourceNode = 0;
517
518     // 2 - If there are any tasks from the media element's media element event task source in 
519     // one of the task queues, then remove those tasks.
520     cancelPendingEventsAndCallbacks();
521
522     // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
523     // a task to fire a simple event named abort at the media element.
524     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
525         scheduleEvent(eventNames().abortEvent);
526
527 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
528     m_player = MediaPlayer::create(this);
529 #else
530     if (m_player)
531         m_player->cancelLoad();
532     else
533         createMediaPlayerProxy();
534 #endif
535
536     // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
537     if (m_networkState != NETWORK_EMPTY) {
538         m_networkState = NETWORK_EMPTY;
539         m_readyState = HAVE_NOTHING;
540         m_readyStateMaximum = HAVE_NOTHING;
541         refreshCachedTime();
542         m_paused = true;
543         m_seeking = false;
544         invalidateCachedTime();
545         scheduleEvent(eventNames().emptiedEvent);
546     }
547
548     // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
549     setPlaybackRate(defaultPlaybackRate());
550
551     // 6 - Set the error attribute to null and the autoplaying flag to true.
552     m_error = 0;
553     m_autoplaying = true;
554
555     // 7 - Invoke the media element's resource selection algorithm.
556
557     // 8 - Note: Playback of any previously playing media resource for this element stops.
558
559     // The resource selection algorithm
560     // 1 - Set the networkState to NETWORK_NO_SOURCE
561     m_networkState = NETWORK_NO_SOURCE;
562
563     // 2 - Asynchronously await a stable state.
564
565     m_playedTimeRanges = TimeRanges::create();
566     m_lastSeekTime = 0;
567     m_closedCaptionsVisible = false;
568
569     // The spec doesn't say to block the load event until we actually run the asynchronous section
570     // algorithm, but do it now because we won't start that until after the timer fires and the 
571     // event may have already fired by then.
572     setShouldDelayLoadEvent(true);
573 }
574
575 void HTMLMediaElement::loadInternal()
576 {
577     // If we can't start a load right away, start it later.
578     Page* page = document()->page();
579     if (page && !page->canStartMedia()) {
580         if (m_isWaitingUntilMediaCanStart)
581             return;
582         document()->addMediaCanStartListener(this);
583         m_isWaitingUntilMediaCanStart = true;
584         return;
585     }
586
587     selectMediaResource();
588 }
589
590 void HTMLMediaElement::selectMediaResource()
591 {
592     LOG(Media, "HTMLMediaElement::selectMediaResource");
593
594     enum Mode { attribute, children };
595     Mode mode = attribute;
596
597     // 3 - ... the media element has neither a src attribute ...
598     if (!hasAttribute(srcAttr)) {
599         // ... nor a source element child: ...
600         Node* node;
601         for (node = firstChild(); node; node = node->nextSibling()) {
602             if (node->hasTagName(sourceTag))
603                 break;
604         }
605
606         if (!node) {
607             m_loadState = WaitingForSource;
608             setShouldDelayLoadEvent(false);
609
610             // ... set the networkState to NETWORK_EMPTY, and abort these steps
611             m_networkState = NETWORK_EMPTY;
612
613             LOG(Media, "HTMLMediaElement::selectMediaResource, nothing to load");
614             return;
615         }
616
617         mode = children;
618     }
619
620     // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event), 
621     // and set its networkState to NETWORK_LOADING.
622     setShouldDelayLoadEvent(true);
623     m_networkState = NETWORK_LOADING;
624
625     // 5
626     scheduleEvent(eventNames().loadstartEvent);
627
628     // 6 - If mode is attribute, then run these substeps
629     if (mode == attribute) {
630         // If the src attribute's value is the empty string ... jump down to the failed step below
631         KURL mediaURL = getNonEmptyURLAttribute(srcAttr);
632         if (mediaURL.isEmpty()) {
633             noneSupported();
634             LOG(Media, "HTMLMediaElement::selectMediaResource, empty 'src'");
635             return;
636         }
637
638         if (isSafeToLoadURL(mediaURL, Complain) && dispatchBeforeLoadEvent(mediaURL.string())) {
639             ContentType contentType("");
640             m_loadState = LoadingFromSrcAttr;
641             loadResource(mediaURL, contentType);
642         } else 
643             noneSupported();
644
645         LOG(Media, "HTMLMediaElement::selectMediaResource, 'src' not used");
646         return;
647     }
648
649     // Otherwise, the source elements will be used
650     m_currentSourceNode = 0;
651     loadNextSourceChild();
652 }
653
654 void HTMLMediaElement::loadNextSourceChild()
655 {
656     ContentType contentType("");
657     KURL mediaURL = selectNextSourceChild(&contentType, Complain);
658     if (!mediaURL.isValid()) {
659         waitForSourceChange();
660         return;
661     }
662
663 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
664     // Recreate the media player for the new url
665     m_player = MediaPlayer::create(this);
666 #endif
667
668     m_loadState = LoadingFromSourceElement;
669     loadResource(mediaURL, contentType);
670 }
671
672 void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& contentType)
673 {
674     ASSERT(isSafeToLoadURL(initialURL, Complain));
675
676     LOG(Media, "HTMLMediaElement::loadResource(%s, %s)", urlForLogging(initialURL.string()).utf8().data(), contentType.raw().utf8().data());
677
678     Frame* frame = document()->frame();
679     if (!frame)
680         return;
681     FrameLoader* loader = frame->loader();
682     if (!loader)
683         return;
684
685     KURL url(initialURL);
686     if (!loader->willLoadMediaElementURL(url))
687         return;
688
689     // The resource fetch algorithm 
690     m_networkState = NETWORK_LOADING;
691
692     m_currentSrc = url;
693
694     LOG(Media, "HTMLMediaElement::loadResource - m_currentSrc -> %s", urlForLogging(m_currentSrc).utf8().data());
695
696     if (m_sendProgressEvents) 
697         startProgressEventTimer();
698
699     if (!autoplay())
700         m_player->setPreload(m_preload);
701     m_player->setPreservesPitch(m_webkitPreservesPitch);
702     updateVolume();
703
704     m_player->load(m_currentSrc, contentType);
705
706     // If there is no poster to display, allow the media engine to render video frames as soon as
707     // they are available.
708     updateDisplayState();
709
710     if (renderer())
711         renderer()->updateFromElement();
712 }
713
714 bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
715 {
716     if (!url.isValid()) {
717         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE because url is invalid", urlForLogging(url.string()).utf8().data());
718         return false;
719     }
720
721     Frame* frame = document()->frame();
722     if (!frame || !document()->securityOrigin()->canDisplay(url)) {
723         if (actionIfInvalid == Complain)
724             FrameLoader::reportLocalLoadFailed(frame, url.string());
725         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE rejected by SecurityOrigin", urlForLogging(url.string()).utf8().data());
726         return false;
727     }
728
729     return true;
730 }
731
732 void HTMLMediaElement::startProgressEventTimer()
733 {
734     if (m_progressEventTimer.isActive())
735         return;
736
737     m_previousProgressTime = WTF::currentTime();
738     m_previousProgress = 0;
739     // 350ms is not magic, it is in the spec!
740     m_progressEventTimer.startRepeating(0.350);
741 }
742
743 void HTMLMediaElement::waitForSourceChange()
744 {
745     LOG(Media, "HTMLMediaElement::waitForSourceChange");
746
747     stopPeriodicTimers();
748     m_loadState = WaitingForSource;
749
750     // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
751     m_networkState = NETWORK_NO_SOURCE;
752
753     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
754     setShouldDelayLoadEvent(false);
755 }
756
757 void HTMLMediaElement::noneSupported()
758 {
759     LOG(Media, "HTMLMediaElement::noneSupported");
760
761     stopPeriodicTimers();
762     m_loadState = WaitingForSource;
763     m_currentSourceNode = 0;
764
765     // 5 - Reaching this step indicates that either the URL failed to resolve, or the media
766     // resource failed to load. Set the error attribute to a new MediaError object whose
767     // code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
768     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
769
770     // 6 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
771     m_networkState = NETWORK_NO_SOURCE;
772
773     // 7 - Queue a task to fire a progress event called error at the media element, in
774     // the context of the fetching process that was used to try to obtain the media
775     // resource in the resource fetch algorithm.
776     scheduleEvent(eventNames().errorEvent);
777
778     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
779     setShouldDelayLoadEvent(false);
780
781     // 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
782
783     updateDisplayState();
784
785     if (renderer())
786         renderer()->updateFromElement();
787 }
788
789 void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
790 {
791     LOG(Media, "HTMLMediaElement::mediaEngineError(%d)", static_cast<int>(err->code()));
792
793     // 1 - The user agent should cancel the fetching process.
794     stopPeriodicTimers();
795     m_loadState = WaitingForSource;
796
797     // 2 - Set the error attribute to a new MediaError object whose code attribute is 
798     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
799     m_error = err;
800
801     // 3 - Queue a task to fire a simple event named error at the media element.
802     scheduleEvent(eventNames().errorEvent);
803
804     // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
805     // task to fire a simple event called emptied at the element.
806     m_networkState = NETWORK_EMPTY;
807     scheduleEvent(eventNames().emptiedEvent);
808
809     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
810     setShouldDelayLoadEvent(false);
811
812     // 6 - Abort the overall resource selection algorithm.
813     m_currentSourceNode = 0;
814 }
815
816 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
817 {
818     LOG(Media, "HTMLMediaElement::cancelPendingEventsAndCallbacks");
819
820     m_pendingEvents.clear();
821
822     for (Node* node = firstChild(); node; node = node->nextSibling()) {
823         if (node->hasTagName(sourceTag))
824             static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
825     }
826 }
827
828 Document* HTMLMediaElement::mediaPlayerOwningDocument()
829 {
830     Document* d = document();
831     
832     if (!d)
833         d = ownerDocument();
834     
835     return d;
836 }
837
838 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
839 {
840     beginProcessingMediaPlayerCallback();
841     setNetworkState(m_player->networkState());
842     endProcessingMediaPlayerCallback();
843 }
844
845 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
846 {
847     LOG(Media, "HTMLMediaElement::setNetworkState(%d) - current state is %d", static_cast<int>(state), static_cast<int>(m_networkState));
848
849     if (state == MediaPlayer::Empty) {
850         // Just update the cached state and leave, we can't do anything.
851         m_networkState = NETWORK_EMPTY;
852         return;
853     }
854
855     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
856         stopPeriodicTimers();
857
858         // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
859         // <source> children, schedule the next one
860         if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
861
862             if (m_currentSourceNode)
863                 m_currentSourceNode->scheduleErrorEvent();
864             else
865                 LOG(Media, "HTMLMediaElement::setNetworkState - error event not sent, <source> was removed");
866
867             if (havePotentialSourceChild()) {
868                 LOG(Media, "HTMLMediaElement::setNetworkState - scheduling next <source>");
869                 scheduleNextSourceChild();
870             } else {
871                 LOG(Media, "HTMLMediaElement::setNetworkState - no more <source> elements, waiting");
872                 waitForSourceChange();
873             }
874
875             return;
876         }
877
878         if (state == MediaPlayer::NetworkError)
879             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
880         else if (state == MediaPlayer::DecodeError)
881             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
882         else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr)
883             noneSupported();
884
885         updateDisplayState();
886         return;
887     }
888
889     if (state == MediaPlayer::Idle) {
890         if (m_networkState > NETWORK_IDLE) {
891             m_progressEventTimer.stop();
892             scheduleEvent(eventNames().suspendEvent);
893         }
894         m_networkState = NETWORK_IDLE;
895     }
896
897     if (state == MediaPlayer::Loading) {
898         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
899             startProgressEventTimer();
900         m_networkState = NETWORK_LOADING;
901     }
902
903     if (state == MediaPlayer::Loaded) {
904         if (m_networkState != NETWORK_IDLE) {
905             m_progressEventTimer.stop();
906
907             // Schedule one last progress event so we guarantee that at least one is fired
908             // for files that load very quickly.
909             scheduleEvent(eventNames().progressEvent);
910         }
911         m_networkState = NETWORK_IDLE;
912         m_completelyLoaded = true;
913     }
914 }
915
916 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
917 {
918     beginProcessingMediaPlayerCallback();
919
920     setReadyState(m_player->readyState());
921
922     endProcessingMediaPlayerCallback();
923 }
924
925 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
926 {
927     LOG(Media, "HTMLMediaElement::setReadyState(%d) - current state is %d,", static_cast<int>(state), static_cast<int>(m_readyState));
928
929     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
930     bool wasPotentiallyPlaying = potentiallyPlaying();
931
932     ReadyState oldState = m_readyState;
933     m_readyState = static_cast<ReadyState>(state);
934
935     if (m_readyState == oldState)
936         return;
937     
938     if (oldState > m_readyStateMaximum)
939         m_readyStateMaximum = oldState;
940
941     if (m_networkState == NETWORK_EMPTY)
942         return;
943
944     if (m_seeking) {
945         // 4.8.10.9, step 11
946         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
947             scheduleEvent(eventNames().waitingEvent);
948
949         // 4.8.10.10 step 14 & 15.
950         if (m_readyState >= HAVE_CURRENT_DATA)
951             finishSeek();
952     } else {
953         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
954             // 4.8.10.8
955             scheduleTimeupdateEvent(false);
956             scheduleEvent(eventNames().waitingEvent);
957         }
958     }
959
960     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
961         scheduleEvent(eventNames().durationchangeEvent);
962         scheduleEvent(eventNames().loadedmetadataEvent);
963         if (renderer())
964             renderer()->updateFromElement();
965         m_player->seek(0);
966     }
967
968     bool shouldUpdateDisplayState = false;
969
970     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
971         m_haveFiredLoadedData = true;
972         shouldUpdateDisplayState = true;
973         scheduleEvent(eventNames().loadeddataEvent);
974         setShouldDelayLoadEvent(false);
975     }
976
977     bool isPotentiallyPlaying = potentiallyPlaying();
978     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) {
979         scheduleEvent(eventNames().canplayEvent);
980         if (isPotentiallyPlaying)
981             scheduleEvent(eventNames().playingEvent);
982         shouldUpdateDisplayState = true;
983     }
984
985     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA) {
986         if (oldState <= HAVE_CURRENT_DATA)
987             scheduleEvent(eventNames().canplayEvent);
988
989         scheduleEvent(eventNames().canplaythroughEvent);
990
991         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
992             scheduleEvent(eventNames().playingEvent);
993
994         if (m_autoplaying && m_paused && autoplay()) {
995             m_paused = false;
996             invalidateCachedTime();
997             scheduleEvent(eventNames().playEvent);
998             scheduleEvent(eventNames().playingEvent);
999         }
1000
1001         shouldUpdateDisplayState = true;
1002     }
1003
1004     if (shouldUpdateDisplayState)
1005         updateDisplayState();
1006
1007     updatePlayState();
1008 }
1009
1010 void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
1011 {
1012     ASSERT(m_player);
1013     if (m_networkState != NETWORK_LOADING)
1014         return;
1015
1016     unsigned progress = m_player->bytesLoaded();
1017     double time = WTF::currentTime();
1018     double timedelta = time - m_previousProgressTime;
1019
1020     if (progress == m_previousProgress) {
1021         if (timedelta > 3.0 && !m_sentStalledEvent) {
1022             scheduleEvent(eventNames().stalledEvent);
1023             m_sentStalledEvent = true;
1024         }
1025     } else {
1026         scheduleEvent(eventNames().progressEvent);
1027         m_previousProgress = progress;
1028         m_previousProgressTime = time;
1029         m_sentStalledEvent = false;
1030         if (renderer())
1031             renderer()->updateFromElement();
1032     }
1033 }
1034
1035 void HTMLMediaElement::rewind(float timeDelta)
1036 {
1037     LOG(Media, "HTMLMediaElement::rewind(%f)", timeDelta);
1038
1039     ExceptionCode e;
1040     setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
1041 }
1042
1043 void HTMLMediaElement::returnToRealtime()
1044 {
1045     LOG(Media, "HTMLMediaElement::returnToRealtime");
1046     ExceptionCode e;
1047     setCurrentTime(maxTimeSeekable(), e);
1048 }  
1049
1050 void HTMLMediaElement::addPlayedRange(float start, float end)
1051 {
1052     LOG(Media, "HTMLMediaElement::addPlayedRange(%f, %f)", start, end);
1053     if (!m_playedTimeRanges)
1054         m_playedTimeRanges = TimeRanges::create();
1055     m_playedTimeRanges->add(start, end);
1056 }  
1057
1058 bool HTMLMediaElement::supportsSave() const
1059 {
1060     return m_player ? m_player->supportsSave() : false;
1061 }
1062     
1063 void HTMLMediaElement::seek(float time, ExceptionCode& ec)
1064 {
1065     LOG(Media, "HTMLMediaElement::seek(%f)", time);
1066
1067     // 4.8.9.9 Seeking
1068
1069     // 1 - If the media element's readyState is HAVE_NOTHING, then raise an INVALID_STATE_ERR exception.
1070     if (m_readyState == HAVE_NOTHING || !m_player) {
1071         ec = INVALID_STATE_ERR;
1072         return;
1073     }
1074
1075     // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
1076     refreshCachedTime();
1077     float now = currentTime();
1078
1079     // 2 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
1080     // already running. Abort that other instance of the algorithm without waiting for the step that
1081     // it is running to complete.
1082     // Nothing specific to be done here.
1083
1084     // 3 - Set the seeking IDL attribute to true.
1085     // The flag will be cleared when the engine tells us the time has actually changed.
1086     m_seeking = true;
1087
1088     // 5 - If the new playback position is later than the end of the media resource, then let it be the end 
1089     // of the media resource instead.
1090     time = min(time, duration());
1091
1092     // 6 - If the new playback position is less than the earliest possible position, let it be that position instead.
1093     float earliestTime = m_player->startTime();
1094     time = max(time, earliestTime);
1095
1096     // Ask the media engine for the time value in the movie's time scale before comparing with current time. This
1097     // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's
1098     // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
1099     // not generate a timechanged callback. This means m_seeking will never be cleared and we will never 
1100     // fire a 'seeked' event.
1101 #if !LOG_DISABLED
1102     float mediaTime = m_player->mediaTimeForTimeValue(time);
1103     if (time != mediaTime)
1104         LOG(Media, "HTMLMediaElement::seek(%f) - media timeline equivalent is %f", time, mediaTime);
1105 #endif
1106     time = m_player->mediaTimeForTimeValue(time);
1107
1108     // 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the 
1109     // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute 
1110     // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
1111     // attribute then set the seeking IDL attribute to false and abort these steps.
1112     RefPtr<TimeRanges> seekableRanges = seekable();
1113
1114     // Short circuit seeking to the current time by just firing the events if no seek is required.
1115     // Don't skip calling the media engine if we are in poster mode because a seek should always 
1116     // cancel poster display.
1117     bool noSeekRequired = !seekableRanges->length() || (time == now && displayMode() != Poster);
1118     if (noSeekRequired) {
1119         if (time == now) {
1120             scheduleEvent(eventNames().seekingEvent);
1121             scheduleTimeupdateEvent(false);
1122             scheduleEvent(eventNames().seekedEvent);
1123         }
1124         m_seeking = false;
1125         return;
1126     }
1127     time = seekableRanges->nearest(time);
1128
1129     if (m_playing) {
1130         if (m_lastSeekTime < now)
1131             addPlayedRange(m_lastSeekTime, now);
1132     }
1133     m_lastSeekTime = time;
1134     m_sentEndEvent = false;
1135
1136     // 8 - Set the current playback position to the given new playback position
1137     m_player->seek(time);
1138
1139     // 9 - Queue a task to fire a simple event named seeking at the element.
1140     scheduleEvent(eventNames().seekingEvent);
1141
1142     // 10 - Queue a task to fire a simple event named timeupdate at the element.
1143     scheduleTimeupdateEvent(false);
1144
1145     // 11-15 are handled, if necessary, when the engine signals a readystate change.
1146 }
1147
1148 void HTMLMediaElement::finishSeek()
1149 {
1150     LOG(Media, "HTMLMediaElement::finishSeek");
1151
1152     // 4.8.10.9 Seeking step 14
1153     m_seeking = false;
1154
1155     // 4.8.10.9 Seeking step 15
1156     scheduleEvent(eventNames().seekedEvent);
1157
1158     setDisplayMode(Video);
1159 }
1160
1161 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
1162 {
1163     return m_readyState;
1164 }
1165
1166 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
1167 {
1168     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
1169 }
1170
1171 bool HTMLMediaElement::hasAudio() const
1172 {
1173     return m_player ? m_player->hasAudio() : false;
1174 }
1175
1176 bool HTMLMediaElement::seeking() const
1177 {
1178     return m_seeking;
1179 }
1180
1181 void HTMLMediaElement::refreshCachedTime() const
1182 {
1183     m_cachedTime = m_player->currentTime();
1184     m_cachedTimeWallClockUpdateTime = WTF::currentTime();
1185 }
1186
1187 void HTMLMediaElement::invalidateCachedTime()
1188 {
1189     LOG(Media, "HTMLMediaElement::invalidateCachedTime");
1190
1191     // Don't try to cache movie time when playback first starts as the time reported by the engine
1192     // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
1193     // too early.
1194     static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
1195
1196     m_minimumWallClockTimeToCacheMediaTime = WTF::currentTime() + minimumTimePlayingBeforeCacheSnapshot;
1197     m_cachedTime = invalidMediaTime;
1198 }
1199
1200 // playback state
1201 float HTMLMediaElement::currentTime() const
1202 {
1203 #if LOG_CACHED_TIME_WARNINGS
1204     static const double minCachedDeltaForWarning = 0.01;
1205 #endif
1206
1207     if (!m_player)
1208         return 0;
1209
1210     if (m_seeking) {
1211         LOG(Media, "HTMLMediaElement::currentTime - seeking, returning %f", m_lastSeekTime);
1212         return m_lastSeekTime;
1213     }
1214
1215     if (m_cachedTime != invalidMediaTime && m_paused) {
1216 #if LOG_CACHED_TIME_WARNINGS
1217         float delta = m_cachedTime - m_player->currentTime();
1218         if (delta > minCachedDeltaForWarning)
1219             LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when paused", delta);
1220 #endif
1221         return m_cachedTime;
1222     }
1223
1224     // Is it too soon use a cached time?
1225     double now = WTF::currentTime();
1226     double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
1227
1228     if (maximumDurationToCacheMediaTime && m_cachedTime != invalidMediaTime && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) {
1229         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
1230
1231         // Not too soon, use the cached time only if it hasn't expired.
1232         if (wallClockDelta < maximumDurationToCacheMediaTime) {
1233             float adjustedCacheTime = static_cast<float>(m_cachedTime + (m_playbackRate * wallClockDelta));
1234
1235 #if LOG_CACHED_TIME_WARNINGS
1236             float delta = adjustedCacheTime - m_player->currentTime();
1237             if (delta > minCachedDeltaForWarning)
1238                 LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when playing", delta);
1239 #endif
1240             return adjustedCacheTime;
1241         }
1242     }
1243
1244 #if LOG_CACHED_TIME_WARNINGS
1245     if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != invalidMediaTime) {
1246         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
1247         float delta = m_cachedTime + (m_playbackRate * wallClockDelta) - m_player->currentTime();
1248         LOG(Media, "HTMLMediaElement::currentTime - cached time was %f seconds off of media time when it expired", delta);
1249     }
1250 #endif
1251
1252     refreshCachedTime();
1253
1254     return m_cachedTime;
1255 }
1256
1257 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
1258 {
1259     seek(time, ec);
1260 }
1261
1262 float HTMLMediaElement::startTime() const
1263 {
1264     if (!m_player)
1265         return 0;
1266     return m_player->startTime();
1267 }
1268
1269 float HTMLMediaElement::duration() const
1270 {
1271     if (m_player && m_readyState >= HAVE_METADATA)
1272         return m_player->duration();
1273
1274     return numeric_limits<float>::quiet_NaN();
1275 }
1276
1277 bool HTMLMediaElement::paused() const
1278 {
1279     return m_paused;
1280 }
1281
1282 float HTMLMediaElement::defaultPlaybackRate() const
1283 {
1284     return m_defaultPlaybackRate;
1285 }
1286
1287 void HTMLMediaElement::setDefaultPlaybackRate(float rate)
1288 {
1289     if (m_defaultPlaybackRate != rate) {
1290         m_defaultPlaybackRate = rate;
1291         scheduleEvent(eventNames().ratechangeEvent);
1292     }
1293 }
1294
1295 float HTMLMediaElement::playbackRate() const
1296 {
1297     return m_player ? m_player->rate() : 0;
1298 }
1299
1300 void HTMLMediaElement::setPlaybackRate(float rate)
1301 {
1302     LOG(Media, "HTMLMediaElement::setPlaybackRate(%f)", rate);
1303
1304     if (m_playbackRate != rate) {
1305         m_playbackRate = rate;
1306         invalidateCachedTime();
1307         scheduleEvent(eventNames().ratechangeEvent);
1308     }
1309     if (m_player && potentiallyPlaying() && m_player->rate() != rate)
1310         m_player->setRate(rate);
1311 }
1312
1313 bool HTMLMediaElement::webkitPreservesPitch() const
1314 {
1315     return m_webkitPreservesPitch;
1316 }
1317
1318 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
1319 {
1320     LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%s)", boolString(preservesPitch));
1321
1322     m_webkitPreservesPitch = preservesPitch;
1323     
1324     if (!m_player)
1325         return;
1326
1327     m_player->setPreservesPitch(preservesPitch);
1328 }
1329
1330 bool HTMLMediaElement::ended() const
1331 {
1332     // 4.8.10.8 Playing the media resource
1333     // The ended attribute must return true if the media element has ended 
1334     // playback and the direction of playback is forwards, and false otherwise.
1335     return endedPlayback() && m_playbackRate > 0;
1336 }
1337
1338 bool HTMLMediaElement::autoplay() const
1339 {
1340     return hasAttribute(autoplayAttr);
1341 }
1342
1343 void HTMLMediaElement::setAutoplay(bool b)
1344 {
1345     LOG(Media, "HTMLMediaElement::setAutoplay(%s)", boolString(b));
1346     setBooleanAttribute(autoplayAttr, b);
1347 }
1348
1349 String HTMLMediaElement::preload() const
1350 {
1351     switch (m_preload) {
1352     case MediaPlayer::None:
1353         return "none";
1354         break;
1355     case MediaPlayer::MetaData:
1356         return "metadata";
1357         break;
1358     case MediaPlayer::Auto:
1359         return "auto";
1360         break;
1361     }
1362
1363     ASSERT_NOT_REACHED();
1364     return String();
1365 }
1366
1367 void HTMLMediaElement::setPreload(const String& preload)
1368 {
1369     LOG(Media, "HTMLMediaElement::setPreload(%s)", preload.utf8().data());
1370     setAttribute(preloadAttr, preload);
1371 }
1372
1373 void HTMLMediaElement::play(bool isUserGesture)
1374 {
1375     LOG(Media, "HTMLMediaElement::play(isUserGesture : %s)", boolString(isUserGesture));
1376
1377     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture)
1378         return;
1379
1380     Document* doc = document();
1381     Settings* settings = doc->settings();
1382     if (settings && settings->needsSiteSpecificQuirks() && m_dispatchingCanPlayEvent && !m_loadInitiatedByUserGesture) {
1383         // It should be impossible to be processing the canplay event while handling a user gesture
1384         // since it is dispatched asynchronously.
1385         ASSERT(!isUserGesture);
1386         String host = doc->baseURL().host();
1387         if (host.endsWith(".npr.org", false) || equalIgnoringCase(host, "npr.org"))
1388             return;
1389     }
1390     
1391     playInternal();
1392 }
1393
1394 void HTMLMediaElement::playInternal()
1395 {
1396     LOG(Media, "HTMLMediaElement::playInternal");
1397
1398     // 4.8.10.9. Playing the media resource
1399     if (!m_player || m_networkState == NETWORK_EMPTY)
1400         scheduleLoad();
1401
1402     if (endedPlayback()) {
1403         ExceptionCode unused;
1404         seek(0, unused);
1405     }
1406     
1407     setPlaybackRate(defaultPlaybackRate());
1408     
1409     if (m_paused) {
1410         m_paused = false;
1411         invalidateCachedTime();
1412         scheduleEvent(eventNames().playEvent);
1413
1414         if (m_readyState <= HAVE_CURRENT_DATA)
1415             scheduleEvent(eventNames().waitingEvent);
1416         else if (m_readyState >= HAVE_FUTURE_DATA)
1417             scheduleEvent(eventNames().playingEvent);
1418     }
1419     m_autoplaying = false;
1420
1421     updatePlayState();
1422 }
1423
1424 void HTMLMediaElement::pause(bool isUserGesture)
1425 {
1426     LOG(Media, "HTMLMediaElement::pause(isUserGesture : %s)", boolString(isUserGesture));
1427
1428     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture)
1429         return;
1430
1431     pauseInternal();
1432 }
1433
1434
1435 void HTMLMediaElement::pauseInternal()
1436 {
1437     LOG(Media, "HTMLMediaElement::pauseInternal");
1438
1439     // 4.8.10.9. Playing the media resource
1440     if (!m_player || m_networkState == NETWORK_EMPTY)
1441         scheduleLoad();
1442
1443     m_autoplaying = false;
1444     
1445     if (!m_paused) {
1446         m_paused = true;
1447         scheduleTimeupdateEvent(false);
1448         scheduleEvent(eventNames().pauseEvent);
1449     }
1450
1451     updatePlayState();
1452 }
1453
1454 bool HTMLMediaElement::loop() const
1455 {
1456     return hasAttribute(loopAttr);
1457 }
1458
1459 void HTMLMediaElement::setLoop(bool b)
1460 {
1461     LOG(Media, "HTMLMediaElement::setLoop(%s)", boolString(b));
1462     setBooleanAttribute(loopAttr, b);
1463 }
1464
1465 bool HTMLMediaElement::controls() const
1466 {
1467     Frame* frame = document()->frame();
1468
1469     // always show controls when scripting is disabled
1470     if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript))
1471         return true;
1472
1473     return hasAttribute(controlsAttr);
1474 }
1475
1476 void HTMLMediaElement::setControls(bool b)
1477 {
1478     LOG(Media, "HTMLMediaElement::setControls(%s)", boolString(b));
1479     setBooleanAttribute(controlsAttr, b);
1480 }
1481
1482 float HTMLMediaElement::volume() const
1483 {
1484     return m_volume;
1485 }
1486
1487 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
1488 {
1489     LOG(Media, "HTMLMediaElement::setVolume(%f)", vol);
1490
1491     if (vol < 0.0f || vol > 1.0f) {
1492         ec = INDEX_SIZE_ERR;
1493         return;
1494     }
1495     
1496     if (m_volume != vol) {
1497         m_volume = vol;
1498         updateVolume();
1499         scheduleEvent(eventNames().volumechangeEvent);
1500     }
1501 }
1502
1503 bool HTMLMediaElement::muted() const
1504 {
1505     return m_muted;
1506 }
1507
1508 void HTMLMediaElement::setMuted(bool muted)
1509 {
1510     LOG(Media, "HTMLMediaElement::setMuted(%s)", boolString(muted));
1511
1512     if (m_muted != muted) {
1513         m_muted = muted;
1514         // Avoid recursion when the player reports volume changes.
1515         if (!processingMediaPlayerCallback()) {
1516             if (m_player) {
1517                 m_player->setMuted(m_muted);
1518                 if (renderer())
1519                     renderer()->updateFromElement();
1520             } else
1521                 updateVolume();
1522         }
1523         scheduleEvent(eventNames().volumechangeEvent);
1524     }
1525 }
1526
1527 void HTMLMediaElement::togglePlayState()
1528 {
1529     LOG(Media, "HTMLMediaElement::togglePlayState - canPlay() is %s", boolString(canPlay()));
1530
1531     // We can safely call the internal play/pause methods, which don't check restrictions, because
1532     // this method is only called from the built-in media controller
1533     if (canPlay())
1534         playInternal();
1535     else 
1536         pauseInternal();
1537 }
1538
1539 void HTMLMediaElement::beginScrubbing()
1540 {
1541     LOG(Media, "HTMLMediaElement::beginScrubbing - paused() is %s", boolString(paused()));
1542
1543     if (!paused()) {
1544         if (ended()) {
1545             // Because a media element stays in non-paused state when it reaches end, playback resumes 
1546             // when the slider is dragged from the end to another position unless we pause first. Do 
1547             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
1548             pause(processingUserGesture());
1549         } else {
1550             // Not at the end but we still want to pause playback so the media engine doesn't try to
1551             // continue playing during scrubbing. Pause without generating an event as we will 
1552             // unpause after scrubbing finishes.
1553             setPausedInternal(true);
1554         }
1555     }
1556 }
1557
1558 void HTMLMediaElement::endScrubbing()
1559 {
1560     LOG(Media, "HTMLMediaElement::endScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal));
1561
1562     if (m_pausedInternal)
1563         setPausedInternal(false);
1564 }
1565
1566 // The spec says to fire periodic timeupdate events (those sent while playing) every
1567 // "15 to 250ms", we choose the slowest frequency
1568 static const double maxTimeupdateEventFrequency = 0.25;
1569
1570 void HTMLMediaElement::startPlaybackProgressTimer()
1571 {
1572     if (m_playbackProgressTimer.isActive())
1573         return;
1574
1575     m_previousProgressTime = WTF::currentTime();
1576     m_previousProgress = 0;
1577     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
1578 }
1579
1580 void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
1581 {
1582     ASSERT(m_player);
1583     if (!m_playbackRate)
1584         return;
1585
1586     scheduleTimeupdateEvent(true);
1587     
1588     // FIXME: deal with cue ranges here
1589 }
1590
1591 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
1592 {
1593     double now = WTF::currentTime();
1594     double timedelta = now - m_lastTimeUpdateEventWallTime;
1595
1596     // throttle the periodic events
1597     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
1598         return;
1599
1600     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
1601     // event at a given time so filter here
1602     float movieTime = currentTime();
1603     if (movieTime != m_lastTimeUpdateEventMovieTime) {
1604         scheduleEvent(eventNames().timeupdateEvent);
1605         m_lastTimeUpdateEventWallTime = now;
1606         m_lastTimeUpdateEventMovieTime = movieTime;
1607     }
1608 }
1609
1610 bool HTMLMediaElement::canPlay() const
1611 {
1612     return paused() || ended() || m_readyState < HAVE_METADATA;
1613 }
1614
1615 float HTMLMediaElement::percentLoaded() const
1616 {
1617     if (!m_player)
1618         return 0;
1619     float duration = m_player->duration();
1620
1621     if (!duration || isinf(duration))
1622         return 0;
1623
1624     float buffered = 0;
1625     RefPtr<TimeRanges> timeRanges = m_player->buffered();
1626     for (unsigned i = 0; i < timeRanges->length(); ++i) {
1627         ExceptionCode ignoredException;
1628         float start = timeRanges->start(i, ignoredException);
1629         float end = timeRanges->end(i, ignoredException);
1630         buffered += end - start;
1631     }
1632     return buffered / duration;
1633 }
1634
1635 bool HTMLMediaElement::havePotentialSourceChild()
1636 {
1637     // Stash the current <source> node and next nodes so we can restore them after checking
1638     // to see there is another potential.
1639     HTMLSourceElement* currentSourceNode = m_currentSourceNode;
1640     Node* nextNode = m_nextChildNodeToConsider;
1641
1642     KURL nextURL = selectNextSourceChild(0, DoNothing);
1643
1644     m_currentSourceNode = currentSourceNode;
1645     m_nextChildNodeToConsider = nextNode;
1646
1647     return nextURL.isValid();
1648 }
1649
1650 KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
1651 {
1652 #if !LOG_DISABLED
1653     // Don't log if this was just called to find out if there are any valid <source> elements.
1654     bool shouldLog = actionIfInvalid != DoNothing;
1655     if (shouldLog)
1656         LOG(Media, "HTMLMediaElement::selectNextSourceChild(contentType : \"%s\")", contentType ? contentType->raw().utf8().data() : "");
1657 #endif
1658
1659     if (m_nextChildNodeToConsider == sourceChildEndOfListValue()) {
1660 #if !LOG_DISABLED
1661         if (shouldLog)
1662             LOG(Media, "HTMLMediaElement::selectNextSourceChild -> 0x0000, \"\"");
1663 #endif
1664         return KURL();
1665     }
1666
1667     KURL mediaURL;
1668     Node* node;
1669     HTMLSourceElement* source = 0;
1670     bool lookingForStartNode = m_nextChildNodeToConsider;
1671     bool canUse = false;
1672
1673     for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
1674         if (lookingForStartNode && m_nextChildNodeToConsider != node)
1675             continue;
1676         lookingForStartNode = false;
1677         
1678         if (!node->hasTagName(sourceTag))
1679             continue;
1680
1681         source = static_cast<HTMLSourceElement*>(node);
1682
1683         // 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
1684         mediaURL = source->getNonEmptyURLAttribute(srcAttr);
1685 #if !LOG_DISABLED
1686         if (shouldLog)
1687             LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'src' is %s", urlForLogging(mediaURL).utf8().data());
1688 #endif
1689         if (mediaURL.isEmpty())
1690             goto check_again;
1691         
1692         if (source->hasAttribute(mediaAttr)) {
1693             MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
1694             RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
1695 #if !LOG_DISABLED
1696             if (shouldLog)
1697                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'media' is %s", source->media().utf8().data());
1698 #endif
1699             if (!screenEval.eval(media.get())) 
1700                 goto check_again;
1701         }
1702
1703         if (source->hasAttribute(typeAttr)) {
1704 #if !LOG_DISABLED
1705             if (shouldLog)
1706                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'type' is %s", source->type().utf8().data());
1707 #endif
1708             if (!MediaPlayer::supportsType(ContentType(source->type())))
1709                 goto check_again;
1710         }
1711
1712         // Is it safe to load this url?
1713         if (!isSafeToLoadURL(mediaURL, actionIfInvalid) || !dispatchBeforeLoadEvent(mediaURL.string()))
1714             goto check_again;
1715
1716         // Making it this far means the <source> looks reasonable.
1717         canUse = true;
1718
1719 check_again:
1720         if (!canUse && actionIfInvalid == Complain)
1721             source->scheduleErrorEvent();
1722     }
1723
1724     if (canUse) {
1725         if (contentType)
1726             *contentType = ContentType(source->type());
1727         m_currentSourceNode = source;
1728         m_nextChildNodeToConsider = source->nextSibling();
1729         if (!m_nextChildNodeToConsider)
1730             m_nextChildNodeToConsider = sourceChildEndOfListValue();
1731     } else {
1732         m_currentSourceNode = 0;
1733         m_nextChildNodeToConsider = sourceChildEndOfListValue();
1734     }
1735
1736 #if !LOG_DISABLED
1737     if (shouldLog)
1738         LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode, canUse ? urlForLogging(mediaURL.string()).utf8().data() : "");
1739 #endif
1740     return canUse ? mediaURL : KURL();
1741 }
1742
1743 void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
1744 {
1745     LOG(Media, "HTMLMediaElement::sourceWasAdded(%p)", source);
1746
1747 #if !LOG_DISABLED
1748     if (source->hasTagName(sourceTag)) {
1749         KURL url = source->getNonEmptyURLAttribute(srcAttr);
1750         LOG(Media, "HTMLMediaElement::sourceWasAdded - 'src' is %s", urlForLogging(url).utf8().data());
1751     }
1752 #endif
1753     
1754     // We should only consider a <source> element when there is not src attribute at all.
1755     if (hasAttribute(srcAttr))
1756         return;
1757
1758     // 4.8.8 - If a source element is inserted as a child of a media element that has no src 
1759     // attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke 
1760     // the media element's resource selection algorithm.
1761     if (networkState() == HTMLMediaElement::NETWORK_EMPTY) {
1762         scheduleLoad();
1763         return;
1764     }
1765
1766     if (m_currentSourceNode && source == m_currentSourceNode->nextSibling()) {
1767         LOG(Media, "HTMLMediaElement::sourceWasAdded - <source> inserted immediately after current source");
1768         m_nextChildNodeToConsider = source;
1769         return;
1770     }
1771
1772     if (m_nextChildNodeToConsider != sourceChildEndOfListValue())
1773         return;
1774     
1775     // 4.8.9.5, resource selection algorithm, source elements section:
1776     // 20 - Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
1777     // 21 - Asynchronously await a stable state...
1778     // 22 - Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case 
1779     // it hasn't been fired yet).
1780     setShouldDelayLoadEvent(true);
1781
1782     // 23 - Set the networkState back to NETWORK_LOADING.
1783     m_networkState = NETWORK_LOADING;
1784     
1785     // 24 - Jump back to the find next candidate step above.
1786     m_nextChildNodeToConsider = source;
1787     scheduleNextSourceChild();
1788 }
1789
1790 void HTMLMediaElement::sourceWillBeRemoved(HTMLSourceElement* source)
1791 {
1792     LOG(Media, "HTMLMediaElement::sourceWillBeRemoved(%p)", source);
1793
1794 #if !LOG_DISABLED
1795     if (source->hasTagName(sourceTag)) {
1796         KURL url = source->getNonEmptyURLAttribute(srcAttr);
1797         LOG(Media, "HTMLMediaElement::sourceWillBeRemoved - 'src' is %s", urlForLogging(url).utf8().data());
1798     }
1799 #endif
1800
1801     if (source != m_currentSourceNode && source != m_nextChildNodeToConsider)
1802         return;
1803
1804     if (source == m_nextChildNodeToConsider) {
1805         m_nextChildNodeToConsider = m_nextChildNodeToConsider->nextSibling();
1806         if (!m_nextChildNodeToConsider)
1807             m_nextChildNodeToConsider = sourceChildEndOfListValue();
1808         LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider);
1809     } else if (source == m_currentSourceNode) {
1810         // Clear the current source node pointer, but don't change the movie as the spec says:
1811         // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already 
1812         // inserted in a video or audio element will have no effect.
1813         m_currentSourceNode = 0;
1814         LOG(Media, "HTMLMediaElement::sourceRemoved - m_currentSourceNode set to 0");
1815     }
1816 }
1817
1818 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
1819 {
1820     LOG(Media, "HTMLMediaElement::mediaPlayerTimeChanged");
1821
1822     beginProcessingMediaPlayerCallback();
1823
1824     invalidateCachedTime();
1825
1826     // 4.8.10.9 step 14 & 15.  Needed if no ReadyState change is associated with the seek.
1827     if (m_seeking && m_readyState >= HAVE_CURRENT_DATA)
1828         finishSeek();
1829     
1830     // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity, 
1831     // it will only queue a 'timeupdate' event if we haven't already posted one at the current
1832     // movie time.
1833     scheduleTimeupdateEvent(false);
1834
1835     float now = currentTime();
1836     float dur = duration();
1837     if (!isnan(dur) && dur && now >= dur) {
1838         if (loop()) {
1839             ExceptionCode ignoredException;
1840             m_sentEndEvent = false;
1841             seek(0, ignoredException);
1842         } else {
1843             if (!m_sentEndEvent) {
1844                 m_sentEndEvent = true;
1845                 scheduleEvent(eventNames().endedEvent);
1846             }
1847         }
1848     }
1849     else
1850         m_sentEndEvent = false;
1851
1852     updatePlayState();
1853     endProcessingMediaPlayerCallback();
1854 }
1855
1856 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
1857 {
1858     LOG(Media, "HTMLMediaElement::mediaPlayerVolumeChanged");
1859
1860     beginProcessingMediaPlayerCallback();
1861     if (m_player)
1862         m_volume = m_player->volume();
1863     updateVolume();
1864     endProcessingMediaPlayerCallback();
1865 }
1866
1867 void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
1868 {
1869     LOG(Media, "HTMLMediaElement::mediaPlayerMuteChanged");
1870
1871     beginProcessingMediaPlayerCallback();
1872     if (m_player)
1873         setMuted(m_player->muted());
1874     endProcessingMediaPlayerCallback();
1875 }
1876
1877 void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
1878 {
1879     LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
1880
1881     beginProcessingMediaPlayerCallback();
1882     scheduleEvent(eventNames().durationchangeEvent);
1883     if (renderer())
1884         renderer()->updateFromElement();
1885     endProcessingMediaPlayerCallback();
1886 }
1887
1888 void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
1889 {
1890     LOG(Media, "HTMLMediaElement::mediaPlayerRateChanged");
1891
1892     beginProcessingMediaPlayerCallback();
1893
1894     invalidateCachedTime();
1895
1896     // Stash the rate in case the one we tried to set isn't what the engine is
1897     // using (eg. it can't handle the rate we set)
1898     m_playbackRate = m_player->rate();
1899     invalidateCachedTime();
1900     endProcessingMediaPlayerCallback();
1901 }
1902
1903 void HTMLMediaElement::mediaPlayerPlaybackStateChanged(MediaPlayer*)
1904 {
1905     LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged");
1906
1907     if (!m_player)
1908         return;
1909
1910     beginProcessingMediaPlayerCallback();
1911     if (m_player->paused())
1912         pauseInternal();
1913     else
1914         playInternal();
1915     endProcessingMediaPlayerCallback();
1916 }
1917
1918 void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
1919 {
1920     LOG(Media, "HTMLMediaElement::mediaPlayerSawUnsupportedTracks");
1921
1922     // The MediaPlayer came across content it cannot completely handle.
1923     // This is normally acceptable except when we are in a standalone
1924     // MediaDocument. If so, tell the document what has happened.
1925     if (ownerDocument()->isMediaDocument()) {
1926         MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
1927         mediaDocument->mediaElementSawUnsupportedTracks();
1928     }
1929 }
1930
1931 // MediaPlayerPresentation methods
1932 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
1933 {
1934     beginProcessingMediaPlayerCallback();
1935     updateDisplayState();
1936     if (renderer())
1937         renderer()->repaint();
1938     endProcessingMediaPlayerCallback();
1939 }
1940
1941 void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
1942 {
1943     LOG(Media, "HTMLMediaElement::mediaPlayerSizeChanged");
1944
1945     beginProcessingMediaPlayerCallback();
1946     if (renderer())
1947         renderer()->updateFromElement();
1948     endProcessingMediaPlayerCallback();
1949 }
1950
1951 #if USE(ACCELERATED_COMPOSITING)
1952 bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
1953 {
1954     if (renderer() && renderer()->isVideo()) {
1955         ASSERT(renderer()->view());
1956         return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
1957     }
1958     return false;
1959 }
1960
1961 void HTMLMediaElement::mediaPlayerRenderingModeChanged(MediaPlayer*)
1962 {
1963     LOG(Media, "HTMLMediaElement::mediaPlayerRenderingModeChanged");
1964
1965     // Kick off a fake recalcStyle that will update the compositing tree.
1966     setNeedsStyleRecalc(SyntheticStyleChange);
1967 }
1968 #endif
1969
1970 void HTMLMediaElement::mediaPlayerEngineUpdated(MediaPlayer*)
1971 {
1972     beginProcessingMediaPlayerCallback();
1973     LOG(Media, "HTMLMediaElement::mediaPlayerEngineUpdated");
1974     if (renderer())
1975         renderer()->updateFromElement();
1976     endProcessingMediaPlayerCallback();
1977 }
1978
1979 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
1980 {
1981     if (!m_player)
1982         return TimeRanges::create();
1983     return m_player->buffered();
1984 }
1985
1986 PassRefPtr<TimeRanges> HTMLMediaElement::played()
1987 {
1988     if (m_playing) {
1989         float time = currentTime();
1990         if (time > m_lastSeekTime)
1991             addPlayedRange(m_lastSeekTime, time);
1992     }
1993
1994     if (!m_playedTimeRanges)
1995         m_playedTimeRanges = TimeRanges::create();
1996
1997     return m_playedTimeRanges->copy();
1998 }
1999
2000 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
2001 {
2002     // FIXME real ranges support
2003     if (!maxTimeSeekable())
2004         return TimeRanges::create();
2005     return TimeRanges::create(minTimeSeekable(), maxTimeSeekable());
2006 }
2007
2008 bool HTMLMediaElement::potentiallyPlaying() const
2009 {
2010     // "pausedToBuffer" means the media engine's rate is 0, but only because it had to stop playing
2011     // when it ran out of buffered data. A movie is this state is "potentially playing", modulo the
2012     // checks in couldPlayIfEnoughData().
2013     bool pausedToBuffer = m_readyStateMaximum >= HAVE_FUTURE_DATA && m_readyState < HAVE_FUTURE_DATA;
2014     return (pausedToBuffer || m_readyState >= HAVE_FUTURE_DATA) && couldPlayIfEnoughData();
2015 }
2016
2017 bool HTMLMediaElement::couldPlayIfEnoughData() const
2018 {
2019     return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
2020 }
2021
2022 bool HTMLMediaElement::endedPlayback() const
2023 {
2024     float dur = duration();
2025     if (!m_player || isnan(dur))
2026         return false;
2027
2028     // 4.8.10.8 Playing the media resource
2029
2030     // A media element is said to have ended playback when the element's 
2031     // readyState attribute is HAVE_METADATA or greater, 
2032     if (m_readyState < HAVE_METADATA)
2033         return false;
2034
2035     // and the current playback position is the end of the media resource and the direction
2036     // of playback is forwards and the media element does not have a loop attribute specified,
2037     float now = currentTime();
2038     if (m_playbackRate > 0)
2039         return dur > 0 && now >= dur && !loop();
2040
2041     // or the current playback position is the earliest possible position and the direction 
2042     // of playback is backwards
2043     if (m_playbackRate < 0)
2044         return now <= 0;
2045
2046     return false;
2047 }
2048
2049 bool HTMLMediaElement::stoppedDueToErrors() const
2050 {
2051     if (m_readyState >= HAVE_METADATA && m_error) {
2052         RefPtr<TimeRanges> seekableRanges = seekable();
2053         if (!seekableRanges->contain(currentTime()))
2054             return true;
2055     }
2056     
2057     return false;
2058 }
2059
2060 bool HTMLMediaElement::pausedForUserInteraction() const
2061 {
2062 //    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
2063     return false;
2064 }
2065
2066 float HTMLMediaElement::minTimeSeekable() const
2067 {
2068     return 0;
2069 }
2070
2071 float HTMLMediaElement::maxTimeSeekable() const
2072 {
2073     return m_player ? m_player->maxTimeSeekable() : 0;
2074 }
2075     
2076 void HTMLMediaElement::updateVolume()
2077 {
2078     if (!m_player)
2079         return;
2080
2081     // Avoid recursion when the player reports volume changes.
2082     if (!processingMediaPlayerCallback()) {
2083         Page* page = document()->page();
2084         float volumeMultiplier = page ? page->mediaVolume() : 1;
2085     
2086         m_player->setMuted(m_muted);
2087         m_player->setVolume(m_volume * volumeMultiplier);
2088     }
2089     
2090     if (renderer())
2091         renderer()->updateFromElement();
2092 }
2093
2094 void HTMLMediaElement::updatePlayState()
2095 {
2096     if (!m_player)
2097         return;
2098
2099     if (m_pausedInternal) {
2100         if (!m_player->paused())
2101             m_player->pause();
2102         refreshCachedTime();
2103         m_playbackProgressTimer.stop();
2104         return;
2105     }
2106     
2107     bool shouldBePlaying = potentiallyPlaying();
2108     bool playerPaused = m_player->paused();
2109
2110     LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, playerPaused = %s", 
2111         boolString(shouldBePlaying), boolString(playerPaused));
2112
2113     if (shouldBePlaying) {
2114         setDisplayMode(Video);
2115         invalidateCachedTime();
2116
2117         if (playerPaused) {
2118             if (!m_isFullscreen && isVideo() && document() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
2119                 enterFullscreen();
2120
2121             // Set rate before calling play in case the rate was set before the media engine was setup.
2122             // The media engine should just stash the rate since it isn't already playing.
2123             m_player->setRate(m_playbackRate);
2124             m_player->play();
2125         }
2126
2127         startPlaybackProgressTimer();
2128         m_playing = true;
2129
2130     } else { // Should not be playing right now
2131         if (!playerPaused)
2132             m_player->pause();
2133         refreshCachedTime();
2134
2135         m_playbackProgressTimer.stop();
2136         m_playing = false;
2137         float time = currentTime();
2138         if (time > m_lastSeekTime)
2139             addPlayedRange(m_lastSeekTime, time);
2140
2141         if (couldPlayIfEnoughData())
2142             m_player->prepareToPlay();
2143     }
2144     
2145     if (renderer())
2146         renderer()->updateFromElement();
2147 }
2148     
2149 void HTMLMediaElement::setPausedInternal(bool b)
2150 {
2151     m_pausedInternal = b;
2152     updatePlayState();
2153 }
2154
2155 void HTMLMediaElement::stopPeriodicTimers()
2156 {
2157     m_progressEventTimer.stop();
2158     m_playbackProgressTimer.stop();
2159 }
2160
2161 void HTMLMediaElement::userCancelledLoad()
2162 {
2163     LOG(Media, "HTMLMediaElement::userCancelledLoad");
2164
2165     if (m_networkState == NETWORK_EMPTY || m_completelyLoaded)
2166         return;
2167
2168     // If the media data fetching process is aborted by the user:
2169
2170     // 1 - The user agent should cancel the fetching process.
2171 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2172     m_player.clear();
2173 #endif
2174     stopPeriodicTimers();
2175     m_loadTimer.stop();
2176     m_loadState = WaitingForSource;
2177
2178     // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED.
2179     m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
2180
2181     // 3 - Queue a task to fire a simple event named error at the media element.
2182     scheduleEvent(eventNames().abortEvent);
2183
2184     // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the 
2185     // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a 
2186     // simple event named emptied at the element. Otherwise, set the element's networkState 
2187     // attribute to the NETWORK_IDLE value.
2188     if (m_readyState == HAVE_NOTHING) {
2189         m_networkState = NETWORK_EMPTY;
2190         scheduleEvent(eventNames().emptiedEvent);
2191     }
2192     else
2193         m_networkState = NETWORK_IDLE;
2194
2195     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
2196     setShouldDelayLoadEvent(false);
2197
2198     // 6 - Abort the overall resource selection algorithm.
2199     m_currentSourceNode = 0;
2200
2201     // Reset m_readyState since m_player is gone.
2202     m_readyState = HAVE_NOTHING;
2203 }
2204
2205 bool HTMLMediaElement::canSuspend() const
2206 {
2207     return true; 
2208 }
2209
2210 void HTMLMediaElement::stop()
2211 {
2212     LOG(Media, "HTMLMediaElement::stop");
2213     if (m_isFullscreen)
2214         exitFullscreen();
2215     
2216     m_inActiveDocument = false;
2217     userCancelledLoad();
2218     
2219     // Stop the playback without generating events
2220     setPausedInternal(true);
2221     
2222     if (renderer())
2223         renderer()->updateFromElement();
2224     
2225     stopPeriodicTimers();
2226     cancelPendingEventsAndCallbacks();
2227 }
2228
2229 void HTMLMediaElement::suspend(ReasonForSuspension why)
2230 {
2231     LOG(Media, "HTMLMediaElement::suspend");
2232     
2233     switch (why)
2234     {
2235         case DocumentWillBecomeInactive:
2236             stop();
2237             break;
2238         case JavaScriptDebuggerPaused:
2239         case WillShowDialog:
2240             // Do nothing, we don't pause media playback in these cases.
2241             break;
2242     }
2243 }
2244
2245 void HTMLMediaElement::resume()
2246 {
2247     LOG(Media, "HTMLMediaElement::resume");
2248
2249     m_inActiveDocument = true;
2250     setPausedInternal(false);
2251
2252     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
2253         // Restart the load if it was aborted in the middle by moving the document to the page cache.
2254         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
2255         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
2256         // This behavior is not specified but it seems like a sensible thing to do.
2257         ExceptionCode ec;
2258         load(processingUserGesture(), ec);
2259     }
2260
2261     if (renderer())
2262         renderer()->updateFromElement();
2263 }
2264
2265 bool HTMLMediaElement::hasPendingActivity() const
2266 {
2267     // Return true when we have pending events so we can't fire events after the JS 
2268     // object gets collected.
2269     bool pending = m_pendingEvents.size();
2270     LOG(Media, "HTMLMediaElement::hasPendingActivity -> %s", boolString(pending));
2271     return pending;
2272 }
2273
2274 void HTMLMediaElement::mediaVolumeDidChange()
2275 {
2276     LOG(Media, "HTMLMediaElement::mediaVolumeDidChange");
2277     updateVolume();
2278 }
2279
2280 void HTMLMediaElement::defaultEventHandler(Event* event)
2281 {
2282 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2283     RenderObject* r = renderer();
2284     if (!r || !r->isWidget())
2285         return;
2286
2287     Widget* widget = toRenderWidget(r)->widget();
2288     if (widget)
2289         widget->handleEvent(event);
2290 #else
2291     if (renderer() && renderer()->isMedia())
2292         toRenderMedia(renderer())->controls()->forwardEvent(event);
2293     if (event->defaultHandled())
2294         return;
2295     HTMLElement::defaultEventHandler(event);
2296 #endif
2297 }
2298
2299 bool HTMLMediaElement::processingUserGesture() const
2300 {
2301     Frame* frame = document()->frame();
2302     FrameLoader* loader = frame ? frame->loader() : 0;
2303
2304     // return 'true' for safety if we don't know the answer 
2305     return loader ? loader->isProcessingUserGesture() : true;
2306 }
2307
2308 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2309
2310 void HTMLMediaElement::ensureMediaPlayer()
2311 {
2312     if (!m_player)
2313         m_player = MediaPlayer::create(this);
2314 }
2315
2316 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
2317 {
2318     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
2319         togglePlayState();
2320         return;
2321     }
2322
2323     if (m_player)
2324         m_player->deliverNotification(notification);
2325 }
2326
2327 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
2328 {
2329     ensureMediaPlayer();
2330     m_player->setMediaPlayerProxy(proxy);
2331 }
2332
2333 void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values)
2334 {
2335     Frame* frame = document()->frame();
2336     FrameLoader* loader = frame ? frame->loader() : 0;
2337
2338     if (isVideo()) {
2339         KURL posterURL = getNonEmptyURLAttribute(posterAttr);
2340         if (!posterURL.isEmpty() && loader && loader->willLoadMediaElementURL(posterURL)) {
2341             names.append("_media_element_poster_");
2342             values.append(posterURL.string());
2343         }
2344     }
2345
2346     if (controls()) {
2347         names.append("_media_element_controls_");
2348         values.append("true");
2349     }
2350
2351     url = src();
2352     if (!isSafeToLoadURL(url, Complain))
2353         url = selectNextSourceChild(0, DoNothing);
2354
2355     m_currentSrc = url.string();
2356     if (url.isValid() && loader && loader->willLoadMediaElementURL(url)) {
2357         names.append("_media_element_src_");
2358         values.append(m_currentSrc);
2359     }
2360 }
2361
2362 void HTMLMediaElement::finishParsingChildren()
2363 {
2364     HTMLElement::finishParsingChildren();
2365     document()->updateStyleIfNeeded();
2366     createMediaPlayerProxy();
2367 }
2368
2369 void HTMLMediaElement::createMediaPlayerProxy()
2370 {
2371     ensureMediaPlayer();
2372
2373     if (m_proxyWidget || (inDocument() && !m_needWidgetUpdate))
2374         return;
2375
2376     Frame* frame = document()->frame();
2377     FrameLoader* loader = frame ? frame->loader() : 0;
2378     if (!loader)
2379         return;
2380
2381     LOG(Media, "HTMLMediaElement::createMediaPlayerProxy");
2382
2383     KURL url;
2384     Vector<String> paramNames;
2385     Vector<String> paramValues;
2386
2387     getPluginProxyParams(url, paramNames, paramValues);
2388     
2389     // Hang onto the proxy widget so it won't be destroyed if the plug-in is set to
2390     // display:none
2391     m_proxyWidget = loader->subframeLoader()->loadMediaPlayerProxyPlugin(this, url, paramNames, paramValues);
2392     if (m_proxyWidget)
2393         m_needWidgetUpdate = false;
2394 }
2395
2396 void HTMLMediaElement::updateWidget(PluginCreationOption)
2397 {
2398     mediaElement->setNeedWidgetUpdate(false);
2399
2400     Vector<String> paramNames;
2401     Vector<String> paramValues;
2402     KURL kurl;
2403     
2404     mediaElement->getPluginProxyParams(kurl, paramNames, paramValues);
2405     SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
2406     loader->loadMediaPlayerProxyPlugin(mediaElement, kurl, paramNames, paramValues);
2407 }
2408
2409 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2410
2411 void HTMLMediaElement::enterFullscreen()
2412 {
2413     LOG(Media, "HTMLMediaElement::enterFullscreen");
2414
2415     ASSERT(!m_isFullscreen);
2416     m_isFullscreen = true;
2417     if (document() && document()->page()) {
2418         document()->page()->chrome()->client()->enterFullscreenForNode(this);
2419         scheduleEvent(eventNames().webkitbeginfullscreenEvent);
2420     }
2421 }
2422
2423 void HTMLMediaElement::exitFullscreen()
2424 {
2425     LOG(Media, "HTMLMediaElement::exitFullscreen");
2426
2427     ASSERT(m_isFullscreen);
2428     m_isFullscreen = false;
2429     if (document() && document()->page()) {
2430         if (document()->page()->chrome()->requiresFullscreenForVideoPlayback())
2431             pauseInternal();
2432         document()->page()->chrome()->client()->exitFullscreenForNode(this);
2433         scheduleEvent(eventNames().webkitendfullscreenEvent);
2434     }
2435 }
2436
2437 PlatformMedia HTMLMediaElement::platformMedia() const
2438 {
2439     return m_player ? m_player->platformMedia() : NoPlatformMedia;
2440 }
2441
2442 #if USE(ACCELERATED_COMPOSITING)
2443 PlatformLayer* HTMLMediaElement::platformLayer() const
2444 {
2445     return m_player ? m_player->platformLayer() : 0;
2446 }
2447 #endif
2448
2449 bool HTMLMediaElement::hasClosedCaptions() const
2450 {
2451     return m_player && m_player->hasClosedCaptions();
2452 }
2453
2454 bool HTMLMediaElement::closedCaptionsVisible() const
2455 {
2456     return m_closedCaptionsVisible;
2457 }
2458
2459 void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
2460 {
2461     LOG(Media, "HTMLMediaElement::setClosedCaptionsVisible(%s)", boolString(closedCaptionVisible));
2462
2463     if (!m_player ||!hasClosedCaptions())
2464         return;
2465
2466     m_closedCaptionsVisible = closedCaptionVisible;
2467     m_player->setClosedCaptionsVisible(closedCaptionVisible);
2468     if (renderer())
2469         renderer()->updateFromElement();
2470 }
2471
2472 void HTMLMediaElement::setWebkitClosedCaptionsVisible(bool visible)
2473 {
2474     setClosedCaptionsVisible(visible);
2475 }
2476
2477 bool HTMLMediaElement::webkitClosedCaptionsVisible() const
2478 {
2479     return closedCaptionsVisible();
2480 }
2481
2482
2483 bool HTMLMediaElement::webkitHasClosedCaptions() const
2484 {
2485     return hasClosedCaptions();
2486 }
2487
2488 #if ENABLE(MEDIA_STATISTICS)
2489 unsigned long HTMLMediaElement::webkitAudioBytesDecoded() const
2490 {
2491     if (!m_player)
2492         return 0;
2493     return m_player->audioBytesDecoded();
2494 }
2495
2496 unsigned long HTMLMediaElement::webkitVideoBytesDecoded() const
2497 {
2498     if (!m_player)
2499         return 0;
2500     return m_player->videoBytesDecoded();
2501 }
2502 #endif
2503
2504 void HTMLMediaElement::mediaCanStart()
2505 {
2506     LOG(Media, "HTMLMediaElement::mediaCanStart");
2507
2508     ASSERT(m_isWaitingUntilMediaCanStart);
2509     m_isWaitingUntilMediaCanStart = false;
2510     loadInternal();
2511 }
2512
2513 bool HTMLMediaElement::isURLAttribute(Attribute* attribute) const
2514 {
2515     return attribute->name() == srcAttr;
2516 }
2517
2518 void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay)
2519 {
2520     if (m_shouldDelayLoadEvent == shouldDelay)
2521         return;
2522
2523     LOG(Media, "HTMLMediaElement::setShouldDelayLoadEvent(%s)", boolString(shouldDelay));
2524
2525     m_shouldDelayLoadEvent = shouldDelay;
2526     if (shouldDelay)
2527         document()->incrementLoadEventDelayCount();
2528     else
2529         document()->decrementLoadEventDelayCount();
2530 }
2531     
2532 }
2533
2534 #endif