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