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