2409d3702d2a20f486ef6c5cfc8d285aff4da6f5
[WebKit.git] / WebCore / html / HTMLMediaElement.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009 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 "CSSHelper.h"
32 #include "CSSPropertyNames.h"
33 #include "CSSValueKeywords.h"
34 #include "ContentType.h"
35 #include "DocLoader.h"
36 #include "Event.h"
37 #include "EventNames.h"
38 #include "ExceptionCode.h"
39 #include "Frame.h"
40 #include "FrameLoader.h"
41 #include "FrameLoaderClient.h"
42 #include "HTMLDocument.h"
43 #include "HTMLNames.h"
44 #include "HTMLSourceElement.h"
45 #include "HTMLVideoElement.h"
46 #include "MIMETypeRegistry.h"
47 #include "MappedAttribute.h"
48 #include "MediaDocument.h"
49 #include "MediaError.h"
50 #include "MediaList.h"
51 #include "MediaPlayer.h"
52 #include "MediaQueryEvaluator.h"
53 #include "Page.h"
54 #include "ProgressEvent.h"
55 #include "RenderVideo.h"
56 #include "ScriptEventListener.h"
57 #include "TimeRanges.h"
58 #include <limits>
59 #include <wtf/CurrentTime.h>
60 #include <wtf/MathExtras.h>
61
62 #if USE(ACCELERATED_COMPOSITING)
63 #include "RenderView.h"
64 #include "RenderLayerCompositor.h"
65 #endif
66
67 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
68 #include "RenderPartObject.h"
69 #include "Widget.h"
70 #endif
71
72 using namespace std;
73
74 namespace WebCore {
75
76 using namespace HTMLNames;
77
78 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc)
79     : HTMLElement(tagName, doc)
80     , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
81     , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
82     , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
83     , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
84     , m_playedTimeRanges()
85     , m_playbackRate(1.0f)
86     , m_defaultPlaybackRate(1.0f)
87     , m_webkitPreservesPitch(true)
88     , m_networkState(NETWORK_EMPTY)
89     , m_readyState(HAVE_NOTHING)
90     , m_volume(1.0f)
91     , m_lastSeekTime(0)
92     , m_previousProgress(0)
93     , m_previousProgressTime(numeric_limits<double>::max())
94     , m_lastTimeUpdateEventWallTime(0)
95     , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max())
96     , m_loadState(WaitingForSource)
97     , m_currentSourceNode(0)
98     , m_player(0)
99     , m_restrictions(NoRestrictions)
100     , m_playing(false)
101     , m_processingMediaPlayerCallback(0)
102     , m_processingLoad(false)
103     , m_delayingTheLoadEvent(false)
104     , m_haveFiredLoadedData(false)
105     , m_inActiveDocument(true)
106     , m_autoplaying(true)
107     , m_muted(false)
108     , m_paused(true)
109     , m_seeking(false)
110     , m_sentStalledEvent(false)
111     , m_sentEndEvent(false)
112     , m_pausedInternal(false)
113     , m_sendProgressEvents(true)
114 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
115     , m_needWidgetUpdate(false)
116 #endif
117 {
118     document()->registerForDocumentActivationCallbacks(this);
119     document()->registerForMediaVolumeCallbacks(this);
120 }
121
122 HTMLMediaElement::~HTMLMediaElement()
123 {
124     document()->unregisterForDocumentActivationCallbacks(this);
125     document()->unregisterForMediaVolumeCallbacks(this);
126 }
127
128 bool HTMLMediaElement::checkDTD(const Node* newChild)
129 {
130     return newChild->hasTagName(sourceTag) || HTMLElement::checkDTD(newChild);
131 }
132
133 void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls)
134 {
135     HTMLElement::attributeChanged(attr, preserveDecls);
136
137     const QualifiedName& attrName = attr->name();
138     if (attrName == srcAttr) {
139         // don't have a src or any <source> children, trigger load
140         if (inDocument() && m_loadState == WaitingForSource)
141             scheduleLoad();
142     } 
143 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
144     else if (attrName == controlsAttr) {
145         if (!isVideo() && attached() && (controls() != (renderer() != 0))) {
146             detach();
147             attach();
148         }
149         if (renderer())
150             renderer()->updateFromElement();
151     }
152 #endif
153 }
154
155 void HTMLMediaElement::parseMappedAttribute(MappedAttribute* attr)
156 {
157     const QualifiedName& attrName = attr->name();
158
159     if (attrName == autobufferAttr) {
160         if (m_player)
161             m_player->setAutobuffer(!attr->isNull());
162     } else if (attrName == onabortAttr)
163         setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
164     else if (attrName == oncanplayAttr)
165         setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, attr));
166     else if (attrName == oncanplaythroughAttr)
167         setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, attr));
168     else if (attrName == ondurationchangeAttr)
169         setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, attr));
170     else if (attrName == onemptiedAttr)
171         setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, attr));
172     else if (attrName == onendedAttr)
173         setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, attr));
174     else if (attrName == onerrorAttr)
175         setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr));
176     else if (attrName == onloadAttr)
177         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
178     else if (attrName == onloadeddataAttr)
179         setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
180     else if (attrName == onloadedmetadataAttr)
181         setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
182     else if (attrName == onloadendAttr)
183         setAttributeEventListener(eventNames().loadendEvent, createAttributeEventListener(this, attr));
184     else if (attrName == onloadstartAttr)
185         setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
186     else if (attrName == onpauseAttr)
187         setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, attr));
188     else if (attrName == onplayAttr)
189         setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, attr));
190     else if (attrName == onplayingAttr)
191         setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, attr));
192     else if (attrName == onprogressAttr)
193         setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, attr));
194     else if (attrName == onratechangeAttr)
195         setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, attr));
196     else if (attrName == onseekedAttr)
197         setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, attr));
198     else if (attrName == onseekingAttr)
199         setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, attr));
200     else if (attrName == onstalledAttr)
201         setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, attr));
202     else if (attrName == onsuspendAttr)
203         setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, attr));
204     else if (attrName == ontimeupdateAttr)
205         setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, attr));
206     else if (attrName == onvolumechangeAttr)
207         setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, attr));
208     else if (attrName == onwaitingAttr)
209         setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, attr));
210     else
211         HTMLElement::parseMappedAttribute(attr);
212 }
213
214 bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style)
215 {
216 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
217     UNUSED_PARAM(style);
218     Frame* frame = document()->frame();
219     if (!frame)
220         return false;
221
222     return true;
223 #else
224     return controls() ? HTMLElement::rendererIsNeeded(style) : false;
225 #endif
226 }
227
228 RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
229 {
230 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
231     return new (arena) RenderPartObject(this);
232 #else
233     return new (arena) RenderMedia(this);
234 #endif
235 }
236  
237 void HTMLMediaElement::insertedIntoDocument()
238 {
239     HTMLElement::insertedIntoDocument();
240     if (!src().isEmpty() && m_networkState == NETWORK_EMPTY)
241         scheduleLoad();
242 }
243
244 void HTMLMediaElement::removedFromDocument()
245 {
246     if (m_networkState > NETWORK_EMPTY)
247         pause();
248     HTMLElement::removedFromDocument();
249 }
250
251 void HTMLMediaElement::attach()
252 {
253     ASSERT(!attached());
254
255 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
256     m_needWidgetUpdate = true;
257 #endif
258
259     HTMLElement::attach();
260
261     if (renderer())
262         renderer()->updateFromElement();
263 }
264
265 void HTMLMediaElement::recalcStyle(StyleChange change)
266 {
267     HTMLElement::recalcStyle(change);
268
269     if (renderer())
270         renderer()->updateFromElement();
271 }
272
273 void HTMLMediaElement::scheduleLoad()
274 {
275     if (m_loadTimer.isActive())
276         return;
277     prepareForLoad();
278     m_loadTimer.startOneShot(0);
279 }
280
281 void HTMLMediaElement::scheduleNextSourceChild()
282 {
283     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
284     m_loadTimer.startOneShot(0);
285 }
286
287 void HTMLMediaElement::scheduleProgressEvent(const AtomicString& eventName)
288 {
289     if (!m_sendProgressEvents)
290         return;
291
292     // FIXME: don't schedule timeupdate or progress events unless there are registered listeners
293
294     bool totalKnown = m_player && m_player->totalBytesKnown();
295     unsigned loaded = m_player ? m_player->bytesLoaded() : 0;
296     unsigned total = m_player ? m_player->totalBytes() : 0;
297
298     RefPtr<ProgressEvent> evt = ProgressEvent::create(eventName, totalKnown, loaded, total);
299     enqueueEvent(evt);
300
301     if (renderer())
302         renderer()->updateFromElement();
303 }
304
305 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
306 {
307     enqueueEvent(Event::create(eventName, false, true));
308 }
309
310 void HTMLMediaElement::enqueueEvent(RefPtr<Event> event)
311 {
312     m_pendingEvents.append(event);
313     if (!m_asyncEventTimer.isActive())
314         m_asyncEventTimer.startOneShot(0);
315 }
316
317 void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
318 {
319     Vector<RefPtr<Event> > pendingEvents;
320     ExceptionCode ec = 0;
321
322     m_pendingEvents.swap(pendingEvents);
323     unsigned count = pendingEvents.size();
324     for (unsigned ndx = 0; ndx < count; ++ndx) 
325         dispatchEvent(pendingEvents[ndx].release(), ec);
326 }
327
328 void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
329 {
330     if (m_loadState == LoadingFromSourceElement)
331         loadNextSourceChild();
332     else
333         loadInternal();
334 }
335
336 static String serializeTimeOffset(float time)
337 {
338     String timeString = String::number(time);
339     // FIXME serialize time offset values properly (format not specified yet)
340     timeString.append("s");
341     return timeString;
342 }
343
344 static float parseTimeOffset(const String& timeString, bool* ok = 0)
345 {
346     const UChar* characters = timeString.characters();
347     unsigned length = timeString.length();
348     
349     if (length && characters[length - 1] == 's')
350         length--;
351     
352     // FIXME parse time offset values (format not specified yet)
353     float val = charactersToFloat(characters, length, ok);
354     return val;
355 }
356
357 float HTMLMediaElement::getTimeOffsetAttribute(const QualifiedName& name, float valueOnError) const
358 {
359     bool ok;
360     String timeString = getAttribute(name);
361     float result = parseTimeOffset(timeString, &ok);
362     if (ok)
363         return result;
364     return valueOnError;
365 }
366
367 void HTMLMediaElement::setTimeOffsetAttribute(const QualifiedName& name, float value)
368 {
369     setAttribute(name, serializeTimeOffset(value));
370 }
371
372 PassRefPtr<MediaError> HTMLMediaElement::error() const 
373 {
374     return m_error;
375 }
376
377 KURL HTMLMediaElement::src() const
378 {
379     return document()->completeURL(getAttribute(srcAttr));
380 }
381
382 void HTMLMediaElement::setSrc(const String& url)
383 {
384     setAttribute(srcAttr, url);
385 }
386
387 String HTMLMediaElement::currentSrc() const
388 {
389     return m_currentSrc;
390 }
391
392 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
393 {
394     return m_networkState;
395 }
396
397 String HTMLMediaElement::canPlayType(const String& mimeType) const
398 {
399     MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType));
400     String canPlay;
401
402     // 4.8.10.3
403     switch (support)
404     {
405         case MediaPlayer::IsNotSupported:
406             canPlay = "";
407             break;
408         case MediaPlayer::MayBeSupported:
409             canPlay = "maybe";
410             break;
411         case MediaPlayer::IsSupported:
412             canPlay = "probably";
413             break;
414     }
415     
416     return canPlay;
417 }
418
419 void HTMLMediaElement::load(ExceptionCode& ec)
420 {
421     if (m_restrictions & RequireUserGestureForLoadRestriction && !processingUserGesture())
422         ec = INVALID_STATE_ERR;
423     else {
424         prepareForLoad();
425         loadInternal();
426     }
427 }
428
429 void HTMLMediaElement::prepareForLoad()
430 {
431     // Perform the cleanup required for the resource load algorithm to run.
432     stopPeriodicTimers();
433     m_loadTimer.stop();
434     m_sentStalledEvent = false;
435     m_haveFiredLoadedData = false;
436
437     // 2 - Abort any already-running instance of the resource selection algorithm for this element.
438     m_currentSourceNode = 0;
439
440     // 3 - If there are any tasks from the media element's media element event task source in 
441     // one of the task queues, then remove those tasks.
442     cancelPendingEventsAndCallbacks();
443 }
444
445 void HTMLMediaElement::loadInternal()
446 {
447     // 1 - If the load() method for this element is already being invoked, then abort these steps.
448     if (m_processingLoad)
449         return;
450     m_processingLoad = true;
451     
452     // Steps 2 and 3 were done in prepareForLoad()
453     
454     // 4 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, set
455     // the error attribute to a new MediaError object whose code attribute is set to
456     // MEDIA_ERR_ABORTED, fire a progress event called abort at the media element, in the
457     // context of the fetching process that is in progress for the element, and fire a progress
458     // event called loadend at the media element, in the context of the same fetching process.
459     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE) {
460         m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
461
462         // fire synchronous 'abort' and 'loadend'
463         bool totalKnown = m_player && m_player->totalBytesKnown();
464         unsigned loaded = m_player ? m_player->bytesLoaded() : 0;
465         unsigned total = m_player ? m_player->totalBytes() : 0;
466         dispatchEvent(ProgressEvent::create(eventNames().abortEvent, totalKnown, loaded, total));
467         dispatchEvent(ProgressEvent::create(eventNames().loadendEvent, totalKnown, loaded, total));
468     }
469
470     // 5
471     m_error = 0;
472     m_autoplaying = true;
473     m_playedTimeRanges = TimeRanges::create();
474     m_lastSeekTime = 0;
475
476     // 6
477     setPlaybackRate(defaultPlaybackRate());
478
479     // 7
480     if (m_networkState != NETWORK_EMPTY) {
481         m_networkState = NETWORK_EMPTY;
482         m_readyState = HAVE_NOTHING;
483         m_paused = true;
484         m_seeking = false;
485         if (m_player) {
486             m_player->pause();
487             m_playing = false;
488             m_player->seek(0);
489         }
490         dispatchEvent(Event::create(eventNames().emptiedEvent, false, true));
491     }
492
493     selectMediaResource();
494     m_processingLoad = false;
495 }
496
497 void HTMLMediaElement::selectMediaResource()
498 {
499     // 1 - If the media element has neither a src attribute nor any source element children, run these substeps
500     String mediaSrc = getAttribute(srcAttr);
501     if (!mediaSrc && !havePotentialSourceChild()) {
502         m_loadState = WaitingForSource;
503
504         // 1 -  Set the networkState to NETWORK_NO_SOURCE
505         m_networkState = NETWORK_NO_SOURCE;
506         
507         // 2 - While the media element has neither a src attribute nor any source element children, 
508         // wait. (This steps might wait forever.)
509
510         m_delayingTheLoadEvent = false;
511         return;
512     }
513
514     // 2
515     m_delayingTheLoadEvent = true;
516
517     // 3
518     m_networkState = NETWORK_LOADING;
519
520     // 4
521     scheduleProgressEvent(eventNames().loadstartEvent);
522
523     // 5 - If the media element has a src attribute, then run these substeps
524     ContentType contentType("");
525     if (!mediaSrc.isEmpty()) {
526         KURL mediaURL = document()->completeURL(mediaSrc);
527         if (isSafeToLoadURL(mediaURL, Complain)) {
528             m_loadState = LoadingFromSrcAttr;
529             loadResource(mediaURL, contentType);
530         } else 
531             noneSupported();
532
533         return;
534     }
535
536     // Otherwise, the source elements will be used
537     m_currentSourceNode = 0;
538     loadNextSourceChild();
539 }
540
541 void HTMLMediaElement::loadNextSourceChild()
542 {
543     ContentType contentType("");
544     KURL mediaURL = selectNextSourceChild(&contentType, Complain);
545     if (!mediaURL.isValid()) {
546         // It seems wrong to fail silently when we give up because no suitable <source>
547         // element can be found and set the error attribute if the element's 'src' attribute
548         // fails, but that is what the spec says.
549         return;
550     }
551
552     m_loadState = LoadingFromSourceElement;
553     loadResource(mediaURL, contentType);
554 }
555
556 void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
557 {
558     ASSERT(isSafeToLoadURL(url, Complain));
559
560     // The resource fetch algorithm 
561     m_networkState = NETWORK_LOADING;
562
563     m_currentSrc = url;
564
565     if (m_sendProgressEvents) 
566         startProgressEventTimer();
567
568 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
569     m_player.clear();
570     m_player.set(new MediaPlayer(this));
571 #else
572     if (!m_player)
573         m_player.set(new MediaPlayer(this));
574 #endif
575
576     m_player->setPreservesPitch(m_webkitPreservesPitch);
577     updateVolume();
578
579     m_player->load(m_currentSrc, contentType);
580     
581     if (renderer())
582         renderer()->updateFromElement();
583 }
584
585 bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
586 {
587     Frame* frame = document()->frame();
588     FrameLoader* loader = frame ? frame->loader() : 0;
589
590     // don't allow remote to local urls, and check with the frame loader client.
591     if (!loader || !loader->canLoad(url, String(), document()) || !loader->client()->shouldLoadMediaElementURL(url)) {
592         if (actionIfInvalid == Complain)
593             FrameLoader::reportLocalLoadFailed(frame, url.string());
594         return false;
595     }
596     
597     return true;
598 }
599
600 void HTMLMediaElement::startProgressEventTimer()
601 {
602     if (m_progressEventTimer.isActive())
603         return;
604
605     m_previousProgressTime = WTF::currentTime();
606     m_previousProgress = 0;
607     // 350ms is not magic, it is in the spec!
608     m_progressEventTimer.startRepeating(0.350);
609 }
610
611 void HTMLMediaElement::noneSupported()
612 {
613     stopPeriodicTimers();
614     m_loadState = WaitingForSource;
615     m_currentSourceNode = 0;
616
617     // 4 - Reaching this step indicates that either the URL failed to resolve, or the media
618     // resource failed to load. Set the error attribute to a new MediaError object whose
619     // code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
620     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
621
622     // 5 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
623     m_networkState = NETWORK_NO_SOURCE;
624
625     // 6 - Queue a task to fire a progress event called error at the media element, in
626     // the context of the fetching process that was used to try to obtain the media
627     // resource in the resource fetch algorithm.
628     scheduleProgressEvent(eventNames().errorEvent);
629
630     // 7 - Queue a task to fire a progress event called loadend at the media element, in
631     // the context of the fetching process that was used to try to obtain the media
632     // resource in the resource fetch algorithm.
633     scheduleProgressEvent(eventNames().loadendEvent);
634
635     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
636     m_delayingTheLoadEvent = false;
637
638     // 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
639
640     if (isVideo())
641         static_cast<HTMLVideoElement*>(this)->updatePosterImage();
642     if (renderer())
643         renderer()->updateFromElement();
644 }
645
646 void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
647 {
648     // 1 - The user agent should cancel the fetching process.
649     stopPeriodicTimers();
650     m_loadState = WaitingForSource;
651
652     // 2 - Set the error attribute to a new MediaError object whose code attribute is 
653     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
654     m_error = err;
655
656     // 3 - Queue a task to fire a progress event called error at the media element, in
657     // the context of the fetching process started by this instance of this algorithm.
658     scheduleProgressEvent(eventNames().errorEvent);
659
660     // 4 - Queue a task to fire a progress event called loadend at the media element, in
661     // the context of the fetching process started by this instance of this algorithm.
662     scheduleProgressEvent(eventNames().loadendEvent);
663
664     // 5 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
665     // task to fire a simple event called emptied at the element.
666     m_networkState = NETWORK_EMPTY;
667     scheduleEvent(eventNames().emptiedEvent);
668
669     // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
670     m_delayingTheLoadEvent = false;
671
672     // 7 - Abort the overall resource selection algorithm.
673     m_currentSourceNode = 0;
674 }
675
676 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
677 {
678     m_pendingEvents.clear();
679
680     for (Node* node = firstChild(); node; node = node->nextSibling()) {
681         if (node->hasTagName(sourceTag))
682             static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
683     }
684 }
685
686 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
687 {
688     beginProcessingMediaPlayerCallback();
689     setNetworkState(m_player->networkState());
690     endProcessingMediaPlayerCallback();
691 }
692
693 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
694 {
695     if (state == MediaPlayer::Empty) {
696         // just update the cached state and leave, we can't do anything 
697         m_networkState = NETWORK_EMPTY;
698         return;
699     }
700
701     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
702         stopPeriodicTimers();
703
704         // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
705         // <source> children, schedule the next one
706         if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
707             m_currentSourceNode->scheduleErrorEvent();
708             if (havePotentialSourceChild())
709                 scheduleNextSourceChild();
710             return;
711         }
712
713         if (state == MediaPlayer::NetworkError)
714             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
715         else if (state == MediaPlayer::DecodeError)
716             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
717         else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr)
718             noneSupported();
719
720         if (isVideo())
721             static_cast<HTMLVideoElement*>(this)->updatePosterImage();
722
723         return;
724     }
725
726     if (state == MediaPlayer::Idle) {
727         if (m_networkState > NETWORK_IDLE) {
728             stopPeriodicTimers();
729             scheduleProgressEvent(eventNames().suspendEvent);
730         }
731         m_networkState = NETWORK_IDLE;
732     }
733
734     if (state == MediaPlayer::Loading) {
735         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
736             startProgressEventTimer();
737         m_networkState = NETWORK_LOADING;
738     }
739
740     if (state == MediaPlayer::Loaded) {
741         NetworkState oldState = m_networkState;
742
743         m_networkState = NETWORK_LOADED;
744         if (oldState < NETWORK_LOADED || oldState == NETWORK_NO_SOURCE) {
745             m_progressEventTimer.stop();
746
747             // Schedule one last progress event so we guarantee that at least one is fired
748             // for files that load very quickly.
749             scheduleProgressEvent(eventNames().progressEvent);
750
751             // Check to see if readyState changes need to be dealt with before sending the 
752             // 'load' event so we report 'canplaythrough' first. This is necessary because a
753             //  media engine reports readyState and networkState changes separately
754             MediaPlayer::ReadyState currentState = m_player->readyState();
755             if (static_cast<ReadyState>(currentState) != m_readyState)
756                 setReadyState(currentState);
757
758             scheduleProgressEvent(eventNames().loadEvent);
759             scheduleProgressEvent(eventNames().loadendEvent);
760         }
761     }
762 }
763
764 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
765 {
766     beginProcessingMediaPlayerCallback();
767
768     setReadyState(m_player->readyState());
769
770     endProcessingMediaPlayerCallback();
771 }
772
773 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
774 {
775     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
776     bool wasPotentiallyPlaying = potentiallyPlaying();
777
778     ReadyState oldState = m_readyState;
779     m_readyState = static_cast<ReadyState>(state);
780
781     if (m_readyState == oldState)
782         return;
783     
784     if (m_networkState == NETWORK_EMPTY)
785         return;
786
787     if (m_seeking) {
788         // 4.8.10.10, step 8
789         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
790             scheduleEvent(eventNames().waitingEvent);
791
792         // 4.8.10.10, step 9
793         if (m_readyState < HAVE_CURRENT_DATA) {
794             if (oldState >= HAVE_CURRENT_DATA)
795                 scheduleEvent(eventNames().seekingEvent);
796         } else {
797             // 4.8.10.10 step 12 & 13.
798             finishSeek();
799         }
800
801     } else {
802         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
803             // 4.8.10.9
804             scheduleTimeupdateEvent(false);
805             scheduleEvent(eventNames().waitingEvent);
806         }
807     }
808
809     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
810         scheduleEvent(eventNames().durationchangeEvent);
811         scheduleEvent(eventNames().loadedmetadataEvent);
812
813 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
814         if (renderer() && renderer()->isVideo()) {
815             toRenderVideo(renderer())->videoSizeChanged();
816         }
817 #endif        
818         m_delayingTheLoadEvent = false;
819         m_player->seek(0);
820     }
821
822     // 4.8.10.7 says loadeddata is sent only when the new state *is* HAVE_CURRENT_DATA: "If the
823     // previous ready state was HAVE_METADATA and the new ready state is HAVE_CURRENT_DATA", 
824     // but the event table at the end of the spec says it is sent when: "readyState newly 
825     // increased to HAVE_CURRENT_DATA  or greater for the first time"
826     // We go with the later because it seems useful to count on getting this event
827     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
828         m_haveFiredLoadedData = true;
829         scheduleEvent(eventNames().loadeddataEvent);
830     }
831
832     bool isPotentiallyPlaying = potentiallyPlaying();
833     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) {
834         scheduleEvent(eventNames().canplayEvent);
835         if (isPotentiallyPlaying)
836             scheduleEvent(eventNames().playingEvent);
837
838         if (isVideo())
839             static_cast<HTMLVideoElement*>(this)->updatePosterImage();
840     }
841
842     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA) {
843         if (oldState <= HAVE_CURRENT_DATA)
844             scheduleEvent(eventNames().canplayEvent);
845
846         scheduleEvent(eventNames().canplaythroughEvent);
847
848         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
849             scheduleEvent(eventNames().playingEvent);
850
851         if (m_autoplaying && m_paused && autoplay()) {
852             m_paused = false;
853             scheduleEvent(eventNames().playEvent);
854             scheduleEvent(eventNames().playingEvent);
855         }
856
857         if (isVideo())
858             static_cast<HTMLVideoElement*>(this)->updatePosterImage();
859     }
860
861     updatePlayState();
862 }
863
864 void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
865 {
866     ASSERT(m_player);
867     if (m_networkState == NETWORK_EMPTY || m_networkState >= NETWORK_LOADED)
868         return;
869
870     unsigned progress = m_player->bytesLoaded();
871     double time = WTF::currentTime();
872     double timedelta = time - m_previousProgressTime;
873
874     if (progress == m_previousProgress) {
875         if (timedelta > 3.0 && !m_sentStalledEvent) {
876             scheduleProgressEvent(eventNames().stalledEvent);
877             m_sentStalledEvent = true;
878         }
879     } else {
880         scheduleProgressEvent(eventNames().progressEvent);
881         m_previousProgress = progress;
882         m_previousProgressTime = time;
883         m_sentStalledEvent = false;
884     }
885 }
886
887 void HTMLMediaElement::rewind(float timeDelta)
888 {
889     ExceptionCode e;
890     setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
891 }
892
893 void HTMLMediaElement::returnToRealtime()
894 {
895     ExceptionCode e;
896     setCurrentTime(maxTimeSeekable(), e);
897 }  
898
899 void HTMLMediaElement::addPlayedRange(float start, float end)
900 {
901     if (!m_playedTimeRanges)
902         m_playedTimeRanges = TimeRanges::create();
903     m_playedTimeRanges->add(start, end);
904 }  
905
906 bool HTMLMediaElement::supportsSave() const
907 {
908     return m_player ? m_player->supportsSave() : false;
909 }
910     
911 void HTMLMediaElement::seek(float time, ExceptionCode& ec)
912 {
913     // 4.8.10.10. Seeking
914     // 1
915     if (m_readyState == HAVE_NOTHING || !m_player) {
916         ec = INVALID_STATE_ERR;
917         return;
918     }
919
920     // 2
921     time = min(time, duration());
922
923     // 3
924     time = max(time, 0.0f);
925
926     // 4
927     RefPtr<TimeRanges> seekableRanges = seekable();
928     if (!seekableRanges->contain(time)) {
929         ec = INDEX_SIZE_ERR;
930         return;
931     }
932     
933     // avoid generating events when the time won't actually change
934     float now = currentTime();
935     if (time == now)
936         return;
937
938     // 5
939     if (m_playing) {
940         if (m_lastSeekTime < now)
941             addPlayedRange(m_lastSeekTime, now);
942     }
943     m_lastSeekTime = time;
944
945     // 6 - set the seeking flag, it will be cleared when the engine tells is the time has actually changed
946     m_seeking = true;
947
948     // 7
949     scheduleTimeupdateEvent(false);
950
951     // 8 - this is covered, if necessary, when the engine signals a readystate change
952
953     // 10
954     m_player->seek(time);
955     m_sentEndEvent = false;
956 }
957
958 void HTMLMediaElement::finishSeek()
959 {
960     // 4.8.10.10 Seeking step 12
961     m_seeking = false;
962
963     // 4.8.10.10 Seeking step 13
964     scheduleEvent(eventNames().seekedEvent);
965 }
966
967 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
968 {
969     return m_readyState;
970 }
971
972 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
973 {
974     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
975 }
976
977 bool HTMLMediaElement::hasAudio() const
978 {
979     return m_player ? m_player->hasAudio() : false;
980 }
981
982 bool HTMLMediaElement::seeking() const
983 {
984     return m_seeking;
985 }
986
987 // playback state
988 float HTMLMediaElement::currentTime() const
989 {
990     if (!m_player)
991         return 0;
992     if (m_seeking)
993         return m_lastSeekTime;
994     return m_player->currentTime();
995 }
996
997 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
998 {
999     seek(time, ec);
1000 }
1001
1002 float HTMLMediaElement::startTime() const
1003 {
1004     if (!m_player)
1005         return 0;
1006     return m_player->startTime();
1007 }
1008
1009 float HTMLMediaElement::duration() const
1010 {
1011     if (m_readyState >= HAVE_METADATA)
1012         return m_player->duration();
1013
1014     return numeric_limits<float>::quiet_NaN();
1015 }
1016
1017 bool HTMLMediaElement::paused() const
1018 {
1019     return m_paused;
1020 }
1021
1022 float HTMLMediaElement::defaultPlaybackRate() const
1023 {
1024     return m_defaultPlaybackRate;
1025 }
1026
1027 void HTMLMediaElement::setDefaultPlaybackRate(float rate)
1028 {
1029     if (m_defaultPlaybackRate != rate) {
1030         m_defaultPlaybackRate = rate;
1031         scheduleEvent(eventNames().ratechangeEvent);
1032     }
1033 }
1034
1035 float HTMLMediaElement::playbackRate() const
1036 {
1037     return m_player ? m_player->rate() : 0;
1038 }
1039
1040 void HTMLMediaElement::setPlaybackRate(float rate)
1041 {
1042     if (m_playbackRate != rate) {
1043         m_playbackRate = rate;
1044         scheduleEvent(eventNames().ratechangeEvent);
1045     }
1046     if (m_player && potentiallyPlaying() && m_player->rate() != rate)
1047         m_player->setRate(rate);
1048 }
1049
1050 bool HTMLMediaElement::webkitPreservesPitch() const
1051 {
1052     return m_webkitPreservesPitch;
1053 }
1054
1055 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
1056 {
1057     m_webkitPreservesPitch = preservesPitch;
1058     
1059     if (!m_player)
1060         return;
1061
1062     m_player->setPreservesPitch(preservesPitch);
1063 }
1064
1065 bool HTMLMediaElement::ended() const
1066 {
1067     return endedPlayback();
1068 }
1069
1070 bool HTMLMediaElement::autoplay() const
1071 {
1072     return hasAttribute(autoplayAttr);
1073 }
1074
1075 void HTMLMediaElement::setAutoplay(bool b)
1076 {
1077     setBooleanAttribute(autoplayAttr, b);
1078 }
1079
1080 bool HTMLMediaElement::autobuffer() const
1081 {
1082     return hasAttribute(autobufferAttr);
1083 }
1084
1085 void HTMLMediaElement::setAutobuffer(bool b)
1086 {
1087     setBooleanAttribute(autobufferAttr, b);
1088 }
1089
1090 void HTMLMediaElement::play()
1091 {
1092     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !processingUserGesture())
1093         return;
1094
1095     playInternal();
1096 }
1097
1098 void HTMLMediaElement::playInternal()
1099 {
1100     // 4.8.10.9. Playing the media resource
1101     if (!m_player || m_networkState == NETWORK_EMPTY)
1102         scheduleLoad();
1103
1104     if (endedPlayback()) {
1105         ExceptionCode unused;
1106         seek(0, unused);
1107     }
1108     
1109     setPlaybackRate(defaultPlaybackRate());
1110     
1111     if (m_paused) {
1112         m_paused = false;
1113         scheduleEvent(eventNames().playEvent);
1114
1115         if (m_readyState <= HAVE_CURRENT_DATA)
1116             scheduleEvent(eventNames().waitingEvent);
1117         else if (m_readyState >= HAVE_FUTURE_DATA)
1118             scheduleEvent(eventNames().playingEvent);
1119     }
1120     m_autoplaying = false;
1121
1122     updatePlayState();
1123 }
1124
1125 void HTMLMediaElement::pause()
1126 {
1127     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !processingUserGesture())
1128         return;
1129
1130     pauseInternal();
1131 }
1132
1133
1134 void HTMLMediaElement::pauseInternal()
1135 {
1136     // 4.8.10.9. Playing the media resource
1137     if (!m_player || m_networkState == NETWORK_EMPTY)
1138         scheduleLoad();
1139
1140     m_autoplaying = false;
1141     
1142     if (!m_paused) {
1143         m_paused = true;
1144         scheduleTimeupdateEvent(false);
1145         scheduleEvent(eventNames().pauseEvent);
1146     }
1147
1148     updatePlayState();
1149 }
1150
1151 bool HTMLMediaElement::loop() const
1152 {
1153     return hasAttribute(loopAttr);
1154 }
1155
1156 void HTMLMediaElement::setLoop(bool b)
1157 {
1158     setBooleanAttribute(loopAttr, b);
1159 }
1160
1161 bool HTMLMediaElement::controls() const
1162 {
1163     Frame* frame = document()->frame();
1164
1165     // always show controls when scripting is disabled
1166     if (frame && !frame->script()->isEnabled())
1167         return true;
1168
1169     return hasAttribute(controlsAttr);
1170 }
1171
1172 void HTMLMediaElement::setControls(bool b)
1173 {
1174     setBooleanAttribute(controlsAttr, b);
1175 }
1176
1177 float HTMLMediaElement::volume() const
1178 {
1179     return m_volume;
1180 }
1181
1182 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
1183 {
1184     if (vol < 0.0f || vol > 1.0f) {
1185         ec = INDEX_SIZE_ERR;
1186         return;
1187     }
1188     
1189     if (m_volume != vol) {
1190         m_volume = vol;
1191         updateVolume();
1192         scheduleEvent(eventNames().volumechangeEvent);
1193     }
1194 }
1195
1196 bool HTMLMediaElement::muted() const
1197 {
1198     return m_muted;
1199 }
1200
1201 void HTMLMediaElement::setMuted(bool muted)
1202 {
1203     if (m_muted != muted) {
1204         m_muted = muted;
1205         updateVolume();
1206         scheduleEvent(eventNames().volumechangeEvent);
1207     }
1208 }
1209
1210 void HTMLMediaElement::togglePlayState()
1211 {
1212     // We can safely call the internal play/pause methods, which don't check restrictions, because
1213     // this method is only called from the built-in media controller
1214     if (canPlay())
1215         playInternal();
1216     else 
1217         pauseInternal();
1218 }
1219
1220 void HTMLMediaElement::beginScrubbing()
1221 {
1222     if (!paused()) {
1223         if (ended()) {
1224             // Because a media element stays in non-paused state when it reaches end, playback resumes 
1225             // when the slider is dragged from the end to another position unless we pause first. Do 
1226             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
1227             pause();
1228         } else {
1229             // Not at the end but we still want to pause playback so the media engine doesn't try to
1230             // continue playing during scrubbing. Pause without generating an event as we will 
1231             // unpause after scrubbing finishes.
1232             setPausedInternal(true);
1233         }
1234     }
1235 }
1236
1237 void HTMLMediaElement::endScrubbing()
1238 {
1239     if (m_pausedInternal)
1240         setPausedInternal(false);
1241 }
1242
1243 // The spec says to fire periodic timeupdate events (those sent while playing) every
1244 // "15 to 250ms", we choose the slowest frequency
1245 static const double maxTimeupdateEventFrequency = 0.25;
1246
1247 void HTMLMediaElement::startPlaybackProgressTimer()
1248 {
1249     if (m_playbackProgressTimer.isActive())
1250         return;
1251
1252     m_previousProgressTime = WTF::currentTime();
1253     m_previousProgress = 0;
1254     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
1255 }
1256
1257 void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
1258 {
1259     ASSERT(m_player);
1260     if (!m_playbackRate)
1261         return;
1262
1263     scheduleTimeupdateEvent(true);
1264     
1265     // FIXME: deal with cue ranges here
1266 }
1267
1268 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
1269 {
1270     double now = WTF::currentTime();
1271     double timedelta = now - m_lastTimeUpdateEventWallTime;
1272
1273     // throttle the periodic events
1274     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
1275         return;
1276
1277     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
1278     // event at a given time so filter here
1279     float movieTime = m_player ? m_player->currentTime() : 0;
1280     if (movieTime != m_lastTimeUpdateEventMovieTime) {
1281         scheduleEvent(eventNames().timeupdateEvent);
1282         m_lastTimeUpdateEventWallTime = now;
1283         m_lastTimeUpdateEventMovieTime = movieTime;
1284     }
1285 }
1286
1287 bool HTMLMediaElement::canPlay() const
1288 {
1289     return paused() || ended() || m_readyState < HAVE_METADATA;
1290 }
1291
1292 float HTMLMediaElement::percentLoaded() const
1293 {
1294     if (!m_player)
1295         return 0;
1296     float duration = m_player->duration();
1297
1298     if (!duration || isinf(duration))
1299         return 0;
1300
1301     float buffered = 0;
1302     RefPtr<TimeRanges> timeRanges = m_player->buffered();
1303     for (unsigned i = 0; i < timeRanges->length(); ++i) {
1304         ExceptionCode ignoredException;
1305         float start = timeRanges->start(i, ignoredException);
1306         float end = timeRanges->end(i, ignoredException);
1307         buffered += end - start;
1308     }
1309     return buffered / duration;
1310 }
1311
1312 bool HTMLMediaElement::havePotentialSourceChild()
1313 {
1314     // Stash the current <source> node so we can restore it after checking
1315     // to see there is another potential
1316     HTMLSourceElement* currentSourceNode = m_currentSourceNode;
1317     KURL nextURL = selectNextSourceChild(0, DoNothing);
1318     m_currentSourceNode = currentSourceNode;
1319
1320     return nextURL.isValid();
1321 }
1322
1323 KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
1324 {
1325     KURL mediaURL;
1326     Node* node;
1327     bool lookingForPreviousNode = m_currentSourceNode;
1328     bool canUse = false;
1329
1330     for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
1331         if (!node->hasTagName(sourceTag))
1332             continue;
1333
1334         if (lookingForPreviousNode) {
1335             if (m_currentSourceNode == static_cast<HTMLSourceElement*>(node))
1336                 lookingForPreviousNode = false;
1337             continue;
1338         }
1339
1340         HTMLSourceElement* source = static_cast<HTMLSourceElement*>(node);
1341         if (!source->hasAttribute(srcAttr))
1342             goto check_again; 
1343
1344         if (source->hasAttribute(mediaAttr)) {
1345             MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
1346             RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
1347             if (!screenEval.eval(media.get())) 
1348                 goto check_again;
1349         }
1350
1351         if (source->hasAttribute(typeAttr)) {
1352             if (!MediaPlayer::supportsType(ContentType(source->type())))
1353                 goto check_again;
1354         }
1355
1356         // Is it safe to load this url?
1357         mediaURL = source->src();
1358         if (!mediaURL.isValid() || !isSafeToLoadURL(mediaURL, actionIfInvalid))
1359             goto check_again;
1360
1361         // Making it this far means the <source> looks reasonable
1362         canUse = true;
1363         if (contentType)
1364             *contentType = ContentType(source->type());
1365
1366 check_again:
1367         if (!canUse && actionIfInvalid == Complain)
1368             source->scheduleErrorEvent();
1369         m_currentSourceNode = static_cast<HTMLSourceElement*>(node);
1370     }
1371
1372     if (!canUse)
1373         m_currentSourceNode = 0;
1374     return canUse ? mediaURL : KURL();
1375 }
1376
1377 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
1378 {
1379     beginProcessingMediaPlayerCallback();
1380
1381     // 4.8.10.10 step 12 & 13.  Needed if no ReadyState change is associated with the seek.
1382     if (m_readyState >= HAVE_CURRENT_DATA && m_seeking) {
1383         finishSeek();
1384     }
1385     
1386     float now = currentTime();
1387     float dur = duration();
1388     if (!isnan(dur) && dur && now >= dur) {
1389         if (loop()) {
1390             ExceptionCode ignoredException;
1391             m_sentEndEvent = false;
1392             seek(0, ignoredException);
1393         } else {
1394             if (!m_sentEndEvent) {
1395                 m_sentEndEvent = true;
1396                 scheduleTimeupdateEvent(false);
1397                 scheduleEvent(eventNames().endedEvent);
1398             }
1399         }
1400     }
1401     else
1402         m_sentEndEvent = false;
1403
1404     updatePlayState();
1405     endProcessingMediaPlayerCallback();
1406 }
1407
1408 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
1409 {
1410     beginProcessingMediaPlayerCallback();
1411     updateVolume();
1412     endProcessingMediaPlayerCallback();
1413 }
1414
1415 void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
1416 {
1417     beginProcessingMediaPlayerCallback();
1418     scheduleEvent(eventNames().durationchangeEvent);
1419 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1420     if (renderer()) {
1421         renderer()->updateFromElement();
1422         if (renderer()->isVideo())
1423             toRenderVideo(renderer())->videoSizeChanged();
1424     }
1425 #endif        
1426     endProcessingMediaPlayerCallback();
1427 }
1428
1429 void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
1430 {
1431     beginProcessingMediaPlayerCallback();
1432     // Stash the rate in case the one we tried to set isn't what the engine is
1433     // using (eg. it can't handle the rate we set)
1434     m_playbackRate = m_player->rate();
1435     endProcessingMediaPlayerCallback();
1436 }
1437
1438 void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
1439 {
1440     // The MediaPlayer came across content it cannot completely handle.
1441     // This is normally acceptable except when we are in a standalone
1442     // MediaDocument. If so, tell the document what has happened.
1443     if (ownerDocument()->isMediaDocument()) {
1444         MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
1445         mediaDocument->mediaElementSawUnsupportedTracks();
1446     }
1447 }
1448
1449 // MediaPlayerPresentation methods
1450 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
1451 {
1452     beginProcessingMediaPlayerCallback();
1453     if (renderer())
1454         renderer()->repaint();
1455     endProcessingMediaPlayerCallback();
1456 }
1457
1458 void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
1459 {
1460     beginProcessingMediaPlayerCallback();
1461 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1462     if (renderer() && renderer()->isVideo())
1463         toRenderVideo(renderer())->videoSizeChanged();
1464 #endif        
1465     endProcessingMediaPlayerCallback();
1466 }
1467
1468 #if USE(ACCELERATED_COMPOSITING)
1469 bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
1470 {
1471     if (renderer() && renderer()->isVideo()) {
1472         ASSERT(renderer()->view());
1473         return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
1474     }
1475     return false;
1476 }
1477
1478 GraphicsLayer* HTMLMediaElement::mediaPlayerGraphicsLayer(MediaPlayer*)
1479 {
1480     if (renderer() && renderer()->isVideo())
1481         return toRenderVideo(renderer())->videoGraphicsLayer();
1482     return 0;
1483 }
1484 #endif
1485
1486 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
1487 {
1488     if (!m_player)
1489         return TimeRanges::create();
1490     return m_player->buffered();
1491 }
1492
1493 PassRefPtr<TimeRanges> HTMLMediaElement::played()
1494 {
1495     if (m_playing) {
1496         float time = currentTime();
1497         if (time > m_lastSeekTime)
1498             addPlayedRange(m_lastSeekTime, time);
1499     }
1500
1501     if (!m_playedTimeRanges)
1502         m_playedTimeRanges = TimeRanges::create();
1503
1504     return m_playedTimeRanges->copy();
1505 }
1506
1507 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
1508 {
1509     // FIXME real ranges support
1510     if (!maxTimeSeekable())
1511         return TimeRanges::create();
1512     return TimeRanges::create(minTimeSeekable(), maxTimeSeekable());
1513 }
1514
1515 bool HTMLMediaElement::potentiallyPlaying() const
1516 {
1517     return !paused() && m_readyState >= HAVE_FUTURE_DATA && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
1518 }
1519
1520 bool HTMLMediaElement::endedPlayback() const
1521 {
1522     if (!m_player || m_readyState < HAVE_METADATA)
1523         return false;
1524     
1525     float dur = duration();
1526     return !isnan(dur) && currentTime() >= dur && !loop();
1527 }
1528
1529 bool HTMLMediaElement::stoppedDueToErrors() const
1530 {
1531     if (m_readyState >= HAVE_METADATA && m_error) {
1532         RefPtr<TimeRanges> seekableRanges = seekable();
1533         if (!seekableRanges->contain(currentTime()))
1534             return true;
1535     }
1536     
1537     return false;
1538 }
1539
1540 bool HTMLMediaElement::pausedForUserInteraction() const
1541 {
1542 //    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
1543     return false;
1544 }
1545
1546 float HTMLMediaElement::minTimeSeekable() const
1547 {
1548     return 0;
1549 }
1550
1551 float HTMLMediaElement::maxTimeSeekable() const
1552 {
1553     return m_player ? m_player->maxTimeSeekable() : 0;
1554 }
1555     
1556 void HTMLMediaElement::updateVolume()
1557 {
1558     if (!m_player)
1559         return;
1560
1561     // Avoid recursion when the player reports volume changes.
1562     if (!processingMediaPlayerCallback()) {
1563         Page* page = document()->page();
1564         float volumeMultiplier = page ? page->mediaVolume() : 1;
1565     
1566         m_player->setVolume(m_muted ? 0 : m_volume * volumeMultiplier);
1567     }
1568     
1569     if (renderer())
1570         renderer()->updateFromElement();
1571 }
1572
1573 void HTMLMediaElement::updatePlayState()
1574 {
1575     if (!m_player)
1576         return;
1577
1578     if (m_pausedInternal) {
1579         if (!m_player->paused())
1580             m_player->pause();
1581         m_playbackProgressTimer.stop();
1582         return;
1583     }
1584     
1585     bool shouldBePlaying = potentiallyPlaying();
1586     bool playerPaused = m_player->paused();
1587     if (shouldBePlaying && playerPaused) {
1588         // Set rate before calling play in case the rate was set before the media engine wasn't setup.
1589         // The media engine should just stash the rate since it isn't already playing.
1590         m_player->setRate(m_playbackRate);
1591         m_player->play();
1592         startPlaybackProgressTimer();
1593         m_playing = true;
1594     } else if (!shouldBePlaying && !playerPaused) {
1595         m_player->pause();
1596         m_playbackProgressTimer.stop();
1597         m_playing = false;
1598         float time = currentTime();
1599         if (time > m_lastSeekTime)
1600             addPlayedRange(m_lastSeekTime, time);
1601     }
1602     
1603     if (renderer())
1604         renderer()->updateFromElement();
1605 }
1606     
1607 void HTMLMediaElement::setPausedInternal(bool b)
1608 {
1609     m_pausedInternal = b;
1610     updatePlayState();
1611 }
1612
1613 void HTMLMediaElement::stopPeriodicTimers()
1614 {
1615     m_progressEventTimer.stop();
1616     m_playbackProgressTimer.stop();
1617 }
1618
1619 void HTMLMediaElement::userCancelledLoad()
1620 {
1621     if (m_networkState == NETWORK_EMPTY || m_networkState >= NETWORK_LOADED)
1622         return;
1623
1624     // If the media data fetching process is aborted by the user:
1625
1626     // 1 - The user agent should cancel the fetching process.
1627 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1628     m_player.clear();
1629 #endif
1630     stopPeriodicTimers();
1631
1632     // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORT.
1633     m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
1634
1635     // 3 - Queue a task to fire a progress event called abort at the media element, in the context
1636     // of the fetching process started by this instance of this algorithm.
1637     scheduleProgressEvent(eventNames().abortEvent);
1638
1639     // 4 - Queue a task to fire a progress event called loadend at the media element, in the context
1640     // of the fetching process started by this instance of this algorithm.
1641     scheduleProgressEvent(eventNames().loadendEvent);
1642
1643     // 5 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
1644     // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
1645     // simple event called emptied at the element. Otherwise, set set the element's networkState
1646     // attribute to the NETWORK_IDLE value.
1647     if (m_readyState == HAVE_NOTHING) {
1648         m_networkState = NETWORK_EMPTY;
1649         scheduleEvent(eventNames().emptiedEvent);
1650     }
1651     else
1652         m_networkState = NETWORK_IDLE;
1653
1654     // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1655     m_delayingTheLoadEvent = false;
1656
1657     // 7 - Abort the overall resource selection algorithm.
1658     m_currentSourceNode = 0;
1659 }
1660
1661 void HTMLMediaElement::documentWillBecomeInactive()
1662 {
1663     m_inActiveDocument = false;
1664     userCancelledLoad();
1665
1666     // Stop the playback without generating events
1667     setPausedInternal(true);
1668
1669     if (renderer())
1670         renderer()->updateFromElement();
1671
1672     stopPeriodicTimers();
1673     cancelPendingEventsAndCallbacks();
1674 }
1675
1676 void HTMLMediaElement::documentDidBecomeActive()
1677 {
1678     m_inActiveDocument = true;
1679     setPausedInternal(false);
1680
1681     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
1682         // Restart the load if it was aborted in the middle by moving the document to the page cache.
1683         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
1684         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
1685         // This behavior is not specified but it seems like a sensible thing to do.
1686         ExceptionCode ec;
1687         load(ec);
1688     }
1689
1690     if (renderer())
1691         renderer()->updateFromElement();
1692 }
1693
1694 void HTMLMediaElement::mediaVolumeDidChange()
1695 {
1696     updateVolume();
1697 }
1698
1699 void HTMLMediaElement::defaultEventHandler(Event* event)
1700 {
1701 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1702     RenderObject* r = renderer();
1703     if (!r || !r->isWidget())
1704         return;
1705
1706     Widget* widget = toRenderWidget(r)->widget();
1707     if (widget)
1708         widget->handleEvent(event);
1709 #else
1710     if (renderer() && renderer()->isMedia())
1711         toRenderMedia(renderer())->forwardEvent(event);
1712     if (event->defaultHandled())
1713         return;
1714     HTMLElement::defaultEventHandler(event);
1715 #endif
1716 }
1717
1718 bool HTMLMediaElement::processingUserGesture() const
1719 {
1720     Frame* frame = document()->frame();
1721     FrameLoader* loader = frame ? frame->loader() : 0;
1722
1723     // return 'true' for safety if we don't know the answer 
1724     return loader ? loader->isProcessingUserGesture() : true;
1725 }
1726
1727 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1728
1729 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
1730 {
1731     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
1732         togglePlayState();
1733         return;
1734     }
1735
1736     if (m_player)
1737         m_player->deliverNotification(notification);
1738 }
1739
1740 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
1741 {
1742     if (m_player)
1743         m_player->setMediaPlayerProxy(proxy);
1744 }
1745
1746 String HTMLMediaElement::initialURL()
1747 {
1748     KURL initialSrc = document()->completeURL(getAttribute(srcAttr));
1749     
1750     if (!initialSrc.isValid())
1751         initialSrc = selectNextSourceChild(0, DoNothing);
1752
1753     m_currentSrc = initialSrc.string();
1754
1755     return initialSrc;
1756 }
1757
1758 void HTMLMediaElement::finishParsingChildren()
1759 {
1760     HTMLElement::finishParsingChildren();
1761     if (!m_player)
1762         m_player.set(new MediaPlayer(this));
1763     
1764     document()->updateStyleIfNeeded();
1765     if (m_needWidgetUpdate && renderer())
1766         toRenderPartObject(renderer())->updateWidget(true);
1767 }
1768
1769 #endif
1770
1771 }
1772
1773 #endif