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