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