2009-08-26 Eric Carlson <eric.carlson@apple.com>
[WebKit-https.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         dispatchProgressEvent(eventNames().abortEvent, totalKnown, loaded, total);
467         dispatchProgressEvent(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(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 bool HTMLMediaElement::supportsSave() const
900 {
901     return m_player ? m_player->supportsSave() : false;
902 }
903     
904 void HTMLMediaElement::seek(float time, ExceptionCode& ec)
905 {
906     // 4.8.10.10. Seeking
907     // 1
908     if (m_readyState == HAVE_NOTHING || !m_player) {
909         ec = INVALID_STATE_ERR;
910         return;
911     }
912
913     // 2
914     time = min(time, duration());
915
916     // 3
917     time = max(time, 0.0f);
918
919     // 4
920     RefPtr<TimeRanges> seekableRanges = seekable();
921     if (!seekableRanges->contain(time)) {
922         ec = INDEX_SIZE_ERR;
923         return;
924     }
925     
926     // avoid generating events when the time won't actually change
927     float now = currentTime();
928     if (time == now)
929         return;
930
931     // 5
932     if (m_playing) {
933         if (m_lastSeekTime < now)
934             m_playedTimeRanges->add(m_lastSeekTime, now);
935     }
936     m_lastSeekTime = time;
937
938     // 6 - set the seeking flag, it will be cleared when the engine tells is the time has actually changed
939     m_seeking = true;
940
941     // 7
942     scheduleTimeupdateEvent(false);
943
944     // 8 - this is covered, if necessary, when the engine signals a readystate change
945
946     // 10
947     m_player->seek(time);
948     m_sentEndEvent = false;
949 }
950
951 void HTMLMediaElement::finishSeek()
952 {
953     // 4.8.10.10 Seeking step 12
954     m_seeking = false;
955
956     // 4.8.10.10 Seeking step 13
957     scheduleEvent(eventNames().seekedEvent);
958 }
959
960 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
961 {
962     return m_readyState;
963 }
964
965 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
966 {
967     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
968 }
969
970 bool HTMLMediaElement::hasAudio() const
971 {
972     return m_player ? m_player->hasAudio() : false;
973 }
974
975 bool HTMLMediaElement::seeking() const
976 {
977     return m_seeking;
978 }
979
980 // playback state
981 float HTMLMediaElement::currentTime() const
982 {
983     if (!m_player)
984         return 0;
985     if (m_seeking)
986         return m_lastSeekTime;
987     return m_player->currentTime();
988 }
989
990 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
991 {
992     seek(time, ec);
993 }
994
995 float HTMLMediaElement::startTime() const
996 {
997     if (!m_player)
998         return 0;
999     return m_player->startTime();
1000 }
1001
1002 float HTMLMediaElement::duration() const
1003 {
1004     if (m_readyState >= HAVE_METADATA)
1005         return m_player->duration();
1006
1007     return numeric_limits<float>::quiet_NaN();
1008 }
1009
1010 bool HTMLMediaElement::paused() const
1011 {
1012     return m_paused;
1013 }
1014
1015 float HTMLMediaElement::defaultPlaybackRate() const
1016 {
1017     return m_defaultPlaybackRate;
1018 }
1019
1020 void HTMLMediaElement::setDefaultPlaybackRate(float rate)
1021 {
1022     if (m_defaultPlaybackRate != rate) {
1023         m_defaultPlaybackRate = rate;
1024         scheduleEvent(eventNames().ratechangeEvent);
1025     }
1026 }
1027
1028 float HTMLMediaElement::playbackRate() const
1029 {
1030     return m_player ? m_player->rate() : 0;
1031 }
1032
1033 void HTMLMediaElement::setPlaybackRate(float rate)
1034 {
1035     if (m_playbackRate != rate) {
1036         m_playbackRate = rate;
1037         scheduleEvent(eventNames().ratechangeEvent);
1038     }
1039     if (m_player && potentiallyPlaying() && m_player->rate() != rate)
1040         m_player->setRate(rate);
1041 }
1042
1043 bool HTMLMediaElement::webkitPreservesPitch() const
1044 {
1045     return m_webkitPreservesPitch;
1046 }
1047
1048 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
1049 {
1050     m_webkitPreservesPitch = preservesPitch;
1051     
1052     if (!m_player)
1053         return;
1054
1055     m_player->setPreservesPitch(preservesPitch);
1056 }
1057
1058 bool HTMLMediaElement::ended() const
1059 {
1060     return endedPlayback();
1061 }
1062
1063 bool HTMLMediaElement::autoplay() const
1064 {
1065     return hasAttribute(autoplayAttr);
1066 }
1067
1068 void HTMLMediaElement::setAutoplay(bool b)
1069 {
1070     setBooleanAttribute(autoplayAttr, b);
1071 }
1072
1073 bool HTMLMediaElement::autobuffer() const
1074 {
1075     return hasAttribute(autobufferAttr);
1076 }
1077
1078 void HTMLMediaElement::setAutobuffer(bool b)
1079 {
1080     setBooleanAttribute(autobufferAttr, b);
1081 }
1082
1083 void HTMLMediaElement::play()
1084 {
1085     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !processingUserGesture())
1086         return;
1087
1088     playInternal();
1089 }
1090
1091 void HTMLMediaElement::playInternal()
1092 {
1093     // 4.8.10.9. Playing the media resource
1094     if (!m_player || m_networkState == NETWORK_EMPTY)
1095         scheduleLoad();
1096
1097     if (endedPlayback()) {
1098         ExceptionCode unused;
1099         seek(0, unused);
1100     }
1101     
1102     setPlaybackRate(defaultPlaybackRate());
1103     
1104     if (m_paused) {
1105         m_paused = false;
1106         scheduleEvent(eventNames().playEvent);
1107
1108         if (m_readyState <= HAVE_CURRENT_DATA)
1109             scheduleEvent(eventNames().waitingEvent);
1110         else if (m_readyState >= HAVE_FUTURE_DATA)
1111             scheduleEvent(eventNames().playingEvent);
1112     }
1113     m_autoplaying = false;
1114
1115     updatePlayState();
1116 }
1117
1118 void HTMLMediaElement::pause()
1119 {
1120     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !processingUserGesture())
1121         return;
1122
1123     pauseInternal();
1124 }
1125
1126
1127 void HTMLMediaElement::pauseInternal()
1128 {
1129     // 4.8.10.9. Playing the media resource
1130     if (!m_player || m_networkState == NETWORK_EMPTY)
1131         scheduleLoad();
1132
1133     m_autoplaying = false;
1134     
1135     if (!m_paused) {
1136         m_paused = true;
1137         scheduleTimeupdateEvent(false);
1138         scheduleEvent(eventNames().pauseEvent);
1139     }
1140
1141     updatePlayState();
1142 }
1143
1144 bool HTMLMediaElement::loop() const
1145 {
1146     return hasAttribute(loopAttr);
1147 }
1148
1149 void HTMLMediaElement::setLoop(bool b)
1150 {
1151     setBooleanAttribute(loopAttr, b);
1152 }
1153
1154 bool HTMLMediaElement::controls() const
1155 {
1156     Frame* frame = document()->frame();
1157
1158     // always show controls when scripting is disabled
1159     if (frame && !frame->script()->isEnabled())
1160         return true;
1161
1162     return hasAttribute(controlsAttr);
1163 }
1164
1165 void HTMLMediaElement::setControls(bool b)
1166 {
1167     setBooleanAttribute(controlsAttr, b);
1168 }
1169
1170 float HTMLMediaElement::volume() const
1171 {
1172     return m_volume;
1173 }
1174
1175 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
1176 {
1177     if (vol < 0.0f || vol > 1.0f) {
1178         ec = INDEX_SIZE_ERR;
1179         return;
1180     }
1181     
1182     if (m_volume != vol) {
1183         m_volume = vol;
1184         updateVolume();
1185         scheduleEvent(eventNames().volumechangeEvent);
1186     }
1187 }
1188
1189 bool HTMLMediaElement::muted() const
1190 {
1191     return m_muted;
1192 }
1193
1194 void HTMLMediaElement::setMuted(bool muted)
1195 {
1196     if (m_muted != muted) {
1197         m_muted = muted;
1198         updateVolume();
1199         scheduleEvent(eventNames().volumechangeEvent);
1200     }
1201 }
1202
1203 void HTMLMediaElement::togglePlayState()
1204 {
1205     // We can safely call the internal play/pause methods, which don't check restrictions, because
1206     // this method is only called from the built-in media controller
1207     if (canPlay())
1208         playInternal();
1209     else 
1210         pauseInternal();
1211 }
1212
1213 void HTMLMediaElement::beginScrubbing()
1214 {
1215     if (!paused()) {
1216         if (ended()) {
1217             // Because a media element stays in non-paused state when it reaches end, playback resumes 
1218             // when the slider is dragged from the end to another position unless we pause first. Do 
1219             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
1220             pause();
1221         } else {
1222             // Not at the end but we still want to pause playback so the media engine doesn't try to
1223             // continue playing during scrubbing. Pause without generating an event as we will 
1224             // unpause after scrubbing finishes.
1225             setPausedInternal(true);
1226         }
1227     }
1228 }
1229
1230 void HTMLMediaElement::endScrubbing()
1231 {
1232     if (m_pausedInternal)
1233         setPausedInternal(false);
1234 }
1235
1236 // The spec says to fire periodic timeupdate events (those sent while playing) every
1237 // "15 to 250ms", we choose the slowest frequency
1238 static const double maxTimeupdateEventFrequency = 0.25;
1239
1240 void HTMLMediaElement::startPlaybackProgressTimer()
1241 {
1242     if (m_playbackProgressTimer.isActive())
1243         return;
1244
1245     m_previousProgressTime = WTF::currentTime();
1246     m_previousProgress = 0;
1247     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
1248 }
1249
1250 void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
1251 {
1252     ASSERT(m_player);
1253     if (!m_playbackRate)
1254         return;
1255
1256     scheduleTimeupdateEvent(true);
1257     
1258     // FIXME: deal with cue ranges here
1259 }
1260
1261 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
1262 {
1263     double now = WTF::currentTime();
1264     double timedelta = now - m_lastTimeUpdateEventWallTime;
1265
1266     // throttle the periodic events
1267     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
1268         return;
1269
1270     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
1271     // event at a given time so filter here
1272     float movieTime = m_player ? m_player->currentTime() : 0;
1273     if (movieTime != m_lastTimeUpdateEventMovieTime) {
1274         scheduleEvent(eventNames().timeupdateEvent);
1275         m_lastTimeUpdateEventWallTime = now;
1276         m_lastTimeUpdateEventMovieTime = movieTime;
1277     }
1278 }
1279
1280 bool HTMLMediaElement::canPlay() const
1281 {
1282     return paused() || ended() || m_readyState < HAVE_METADATA;
1283 }
1284
1285 float HTMLMediaElement::percentLoaded() const
1286 {
1287     if (!m_player)
1288         return 0;
1289     float duration = m_player->duration();
1290     return duration ? m_player->maxTimeBuffered() / duration : 0;
1291 }
1292
1293 bool HTMLMediaElement::havePotentialSourceChild()
1294 {
1295     // Stash the current <source> node so we can restore it after checking
1296     // to see there is another potential
1297     HTMLSourceElement* currentSourceNode = m_currentSourceNode;
1298     KURL nextURL = selectNextSourceChild(0, DoNothing);
1299     m_currentSourceNode = currentSourceNode;
1300
1301     return nextURL.isValid();
1302 }
1303
1304 KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
1305 {
1306     KURL mediaURL;
1307     Node* node;
1308     bool lookingForPreviousNode = m_currentSourceNode;
1309     bool canUse = false;
1310
1311     for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
1312         if (!node->hasTagName(sourceTag))
1313             continue;
1314
1315         if (lookingForPreviousNode) {
1316             if (m_currentSourceNode == static_cast<HTMLSourceElement*>(node))
1317                 lookingForPreviousNode = false;
1318             continue;
1319         }
1320
1321         HTMLSourceElement* source = static_cast<HTMLSourceElement*>(node);
1322         if (!source->hasAttribute(srcAttr))
1323             goto check_again; 
1324
1325         if (source->hasAttribute(mediaAttr)) {
1326             MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
1327             RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
1328             if (!screenEval.eval(media.get())) 
1329                 goto check_again;
1330         }
1331
1332         if (source->hasAttribute(typeAttr)) {
1333             if (!MediaPlayer::supportsType(ContentType(source->type())))
1334                 goto check_again;
1335         }
1336
1337         // Is it safe to load this url?
1338         mediaURL = source->src();
1339         if (!mediaURL.isValid() || !isSafeToLoadURL(mediaURL, actionIfInvalid))
1340             goto check_again;
1341
1342         // Making it this far means the <source> looks reasonable
1343         canUse = true;
1344         if (contentType)
1345             *contentType = ContentType(source->type());
1346
1347 check_again:
1348         if (!canUse && actionIfInvalid == Complain)
1349             source->scheduleErrorEvent();
1350         m_currentSourceNode = static_cast<HTMLSourceElement*>(node);
1351     }
1352
1353     if (!canUse)
1354         m_currentSourceNode = 0;
1355     return canUse ? mediaURL : KURL();
1356 }
1357
1358 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
1359 {
1360     beginProcessingMediaPlayerCallback();
1361
1362     // 4.8.10.10 step 12 & 13.  Needed if no ReadyState change is associated with the seek.
1363     if (m_readyState >= HAVE_CURRENT_DATA && m_seeking) {
1364         finishSeek();
1365     }
1366     
1367     float now = currentTime();
1368     float dur = duration();
1369     if (!isnan(dur) && dur && now >= dur) {
1370         if (loop()) {
1371             ExceptionCode ignoredException;
1372             m_sentEndEvent = false;
1373             seek(0, ignoredException);
1374         } else {
1375             if (!m_sentEndEvent) {
1376                 m_sentEndEvent = true;
1377                 scheduleTimeupdateEvent(false);
1378                 scheduleEvent(eventNames().endedEvent);
1379             }
1380         }
1381     }
1382     else
1383         m_sentEndEvent = false;
1384
1385     updatePlayState();
1386     endProcessingMediaPlayerCallback();
1387 }
1388
1389 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
1390 {
1391     beginProcessingMediaPlayerCallback();
1392     updateVolume();
1393     endProcessingMediaPlayerCallback();
1394 }
1395
1396 void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
1397 {
1398     beginProcessingMediaPlayerCallback();
1399     scheduleEvent(eventNames().durationchangeEvent);
1400 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1401     if (renderer()) {
1402         renderer()->updateFromElement();
1403         if (renderer()->isVideo())
1404             toRenderVideo(renderer())->videoSizeChanged();
1405     }
1406 #endif        
1407     endProcessingMediaPlayerCallback();
1408 }
1409
1410 void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
1411 {
1412     beginProcessingMediaPlayerCallback();
1413     // Stash the rate in case the one we tried to set isn't what the engine is
1414     // using (eg. it can't handle the rate we set)
1415     m_playbackRate = m_player->rate();
1416     endProcessingMediaPlayerCallback();
1417 }
1418
1419 void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
1420 {
1421     // The MediaPlayer came across content it cannot completely handle.
1422     // This is normally acceptable except when we are in a standalone
1423     // MediaDocument. If so, tell the document what has happened.
1424     if (ownerDocument()->isMediaDocument()) {
1425         MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
1426         mediaDocument->mediaElementSawUnsupportedTracks();
1427     }
1428 }
1429
1430 // MediaPlayerPresentation methods
1431 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
1432 {
1433     beginProcessingMediaPlayerCallback();
1434     if (renderer())
1435         renderer()->repaint();
1436     endProcessingMediaPlayerCallback();
1437 }
1438
1439 void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
1440 {
1441     beginProcessingMediaPlayerCallback();
1442 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1443     if (renderer() && renderer()->isVideo())
1444         toRenderVideo(renderer())->videoSizeChanged();
1445 #endif        
1446     endProcessingMediaPlayerCallback();
1447 }
1448
1449 #if USE(ACCELERATED_COMPOSITING)
1450 bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
1451 {
1452     if (renderer() && renderer()->isVideo()) {
1453         ASSERT(renderer()->view());
1454         return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
1455     }
1456     return false;
1457 }
1458
1459 GraphicsLayer* HTMLMediaElement::mediaPlayerGraphicsLayer(MediaPlayer*)
1460 {
1461     if (renderer() && renderer()->isVideo())
1462         return toRenderVideo(renderer())->videoGraphicsLayer();
1463     return 0;
1464 }
1465 #endif
1466
1467 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
1468 {
1469     // FIXME real ranges support
1470     if (!m_player || !m_player->maxTimeBuffered())
1471         return TimeRanges::create();
1472     return TimeRanges::create(0, m_player->maxTimeBuffered());
1473 }
1474
1475 PassRefPtr<TimeRanges> HTMLMediaElement::played() const
1476 {
1477     if (!m_playedTimeRanges) {
1478         // We are not yet loaded
1479         return TimeRanges::create();
1480     }
1481     if (m_playing) {
1482         float time = currentTime();
1483         if (m_lastSeekTime < time)
1484             m_playedTimeRanges->add(m_lastSeekTime, time);
1485     }
1486     return m_playedTimeRanges->copy();
1487 }
1488
1489 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
1490 {
1491     // FIXME real ranges support
1492     if (!maxTimeSeekable())
1493         return TimeRanges::create();
1494     return TimeRanges::create(minTimeSeekable(), maxTimeSeekable());
1495 }
1496
1497 bool HTMLMediaElement::potentiallyPlaying() const
1498 {
1499     return !paused() && m_readyState >= HAVE_FUTURE_DATA && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
1500 }
1501
1502 bool HTMLMediaElement::endedPlayback() const
1503 {
1504     if (!m_player || m_readyState < HAVE_METADATA)
1505         return false;
1506     
1507     float dur = duration();
1508     return !isnan(dur) && currentTime() >= dur && !loop();
1509 }
1510
1511 bool HTMLMediaElement::stoppedDueToErrors() const
1512 {
1513     if (m_readyState >= HAVE_METADATA && m_error) {
1514         RefPtr<TimeRanges> seekableRanges = seekable();
1515         if (!seekableRanges->contain(currentTime()))
1516             return true;
1517     }
1518     
1519     return false;
1520 }
1521
1522 bool HTMLMediaElement::pausedForUserInteraction() const
1523 {
1524 //    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
1525     return false;
1526 }
1527
1528 float HTMLMediaElement::minTimeSeekable() const
1529 {
1530     return 0;
1531 }
1532
1533 float HTMLMediaElement::maxTimeSeekable() const
1534 {
1535     return m_player ? m_player->maxTimeSeekable() : 0;
1536 }
1537     
1538 void HTMLMediaElement::updateVolume()
1539 {
1540     if (!m_player)
1541         return;
1542
1543     // Avoid recursion when the player reports volume changes.
1544     if (!processingMediaPlayerCallback()) {
1545         Page* page = document()->page();
1546         float volumeMultiplier = page ? page->mediaVolume() : 1;
1547     
1548         m_player->setVolume(m_muted ? 0 : m_volume * volumeMultiplier);
1549     }
1550     
1551     if (renderer())
1552         renderer()->updateFromElement();
1553 }
1554
1555 void HTMLMediaElement::updatePlayState()
1556 {
1557     if (!m_player)
1558         return;
1559
1560     if (m_pausedInternal) {
1561         if (!m_player->paused())
1562             m_player->pause();
1563         m_playbackProgressTimer.stop();
1564         return;
1565     }
1566     
1567     bool shouldBePlaying = potentiallyPlaying();
1568     bool playerPaused = m_player->paused();
1569     if (shouldBePlaying && playerPaused) {
1570         // Set rate before calling play in case the rate was set before the media engine wasn't setup.
1571         // The media engine should just stash the rate since it isn't already playing.
1572         m_player->setRate(m_playbackRate);
1573         m_player->play();
1574         startPlaybackProgressTimer();
1575         m_playing = true;
1576     } else if (!shouldBePlaying && !playerPaused) {
1577         m_player->pause();
1578         m_playbackProgressTimer.stop();
1579         m_playing = false;
1580         float time = currentTime();
1581         if (m_lastSeekTime < time)
1582             m_playedTimeRanges->add(m_lastSeekTime, time);
1583     }
1584     
1585     if (renderer())
1586         renderer()->updateFromElement();
1587 }
1588     
1589 void HTMLMediaElement::setPausedInternal(bool b)
1590 {
1591     m_pausedInternal = b;
1592     updatePlayState();
1593 }
1594
1595 void HTMLMediaElement::stopPeriodicTimers()
1596 {
1597     m_progressEventTimer.stop();
1598     m_playbackProgressTimer.stop();
1599 }
1600
1601 void HTMLMediaElement::userCancelledLoad()
1602 {
1603     if (m_networkState != NETWORK_EMPTY) {
1604
1605         // If the media data fetching process is aborted by the user:
1606
1607         // 1 - The user agent should cancel the fetching process.
1608 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1609         m_player.clear();
1610 #endif
1611         stopPeriodicTimers();
1612
1613         // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORT.
1614         m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
1615
1616         // 3 - Queue a task to fire a progress event called abort at the media element, in the context
1617         // of the fetching process started by this instance of this algorithm.
1618         scheduleProgressEvent(eventNames().abortEvent);
1619
1620         // 4 - Queue a task to fire a progress event called loadend at the media element, in the context
1621         // of the fetching process started by this instance of this algorithm.
1622         scheduleProgressEvent(eventNames().loadendEvent);
1623
1624         // 5 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
1625         // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
1626         // simple event called emptied at the element. Otherwise, set set the element's networkState
1627         // attribute to the NETWORK_IDLE value.
1628         if (m_networkState >= NETWORK_LOADING) {
1629             m_networkState = NETWORK_EMPTY;
1630             m_readyState = HAVE_NOTHING;
1631             scheduleEvent(eventNames().emptiedEvent);
1632         }
1633
1634         // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1635         m_delayingTheLoadEvent = false;
1636
1637         // 7 - Abort the overall resource selection algorithm.
1638         m_currentSourceNode = 0;
1639     }
1640 }
1641
1642 void HTMLMediaElement::documentWillBecomeInactive()
1643 {
1644     m_inActiveDocument = false;
1645     userCancelledLoad();
1646
1647     // Stop the playback without generating events
1648     setPausedInternal(true);
1649
1650     if (renderer())
1651         renderer()->updateFromElement();
1652
1653     stopPeriodicTimers();
1654     cancelPendingEventsAndCallbacks();
1655 }
1656
1657 void HTMLMediaElement::documentDidBecomeActive()
1658 {
1659     m_inActiveDocument = true;
1660     setPausedInternal(false);
1661
1662     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
1663         // Restart the load if it was aborted in the middle by moving the document to the page cache.
1664         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
1665         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
1666         // This behavior is not specified but it seems like a sensible thing to do.
1667         ExceptionCode ec;
1668         load(ec);
1669     }
1670
1671     if (renderer())
1672         renderer()->updateFromElement();
1673 }
1674
1675 void HTMLMediaElement::mediaVolumeDidChange()
1676 {
1677     updateVolume();
1678 }
1679
1680 void HTMLMediaElement::defaultEventHandler(Event* event)
1681 {
1682 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1683     RenderObject* r = renderer();
1684     if (!r || !r->isWidget())
1685         return;
1686
1687     Widget* widget = toRenderWidget(r)->widget();
1688     if (widget)
1689         widget->handleEvent(event);
1690 #else
1691     if (renderer() && renderer()->isMedia())
1692         toRenderMedia(renderer())->forwardEvent(event);
1693     if (event->defaultHandled())
1694         return;
1695     HTMLElement::defaultEventHandler(event);
1696 #endif
1697 }
1698
1699 bool HTMLMediaElement::processingUserGesture() const
1700 {
1701     Frame* frame = document()->frame();
1702     FrameLoader* loader = frame ? frame->loader() : 0;
1703
1704     // return 'true' for safety if we don't know the answer 
1705     return loader ? loader->isProcessingUserGesture() : true;
1706 }
1707
1708 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1709
1710 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
1711 {
1712     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
1713         togglePlayState();
1714         return;
1715     }
1716
1717     if (m_player)
1718         m_player->deliverNotification(notification);
1719 }
1720
1721 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
1722 {
1723     if (m_player)
1724         m_player->setMediaPlayerProxy(proxy);
1725 }
1726
1727 String HTMLMediaElement::initialURL()
1728 {
1729     KURL initialSrc = document()->completeURL(getAttribute(srcAttr));
1730     
1731     if (!initialSrc.isValid())
1732         initialSrc = selectNextSourceChild(0, DoNothing);
1733
1734     m_currentSrc = initialSrc.string();
1735
1736     return initialSrc;
1737 }
1738
1739 void HTMLMediaElement::finishParsingChildren()
1740 {
1741     HTMLElement::finishParsingChildren();
1742     if (!m_player)
1743         m_player.set(new MediaPlayer(this));
1744     
1745     document()->updateStyleIfNeeded();
1746     if (m_needWidgetUpdate && renderer())
1747         toRenderPartObject(renderer())->updateWidget(true);
1748 }
1749
1750 #endif
1751
1752 }
1753
1754 #endif