2009-02-18 Dimitri Glazkov <dglazkov@chromium.org>
[WebKit-https.git] / WebCore / html / HTMLMediaElement.cpp
1 /*
2  * Copyright (C) 2007, 2008 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 "ContentType.h"
32 #include "CSSHelper.h"
33 #include "CSSPropertyNames.h"
34 #include "CSSValueKeywords.h"
35 #include "Event.h"
36 #include "EventNames.h"
37 #include "ExceptionCode.h"
38 #include "Frame.h"
39 #include "FrameLoader.h"
40 #include "HTMLDocument.h"
41 #include "HTMLNames.h"
42 #include "HTMLSourceElement.h"
43 #include "HTMLVideoElement.h"
44 #include <limits>
45 #include "MediaError.h"
46 #include "MediaList.h"
47 #include "MediaQueryEvaluator.h"
48 #include "MIMETypeRegistry.h"
49 #include "MediaPlayer.h"
50 #include "Page.h"
51 #include "RenderVideo.h"
52 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
53 #include "RenderPartObject.h"
54 #endif
55 #include "TimeRanges.h"
56 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
57 #include "Widget.h"
58 #endif
59 #include <wtf/CurrentTime.h>
60 #include <wtf/MathExtras.h>
61
62 using namespace std;
63
64 namespace WebCore {
65
66 using namespace HTMLNames;
67
68 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc)
69     : HTMLElement(tagName, doc)
70     , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
71     , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
72     , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
73     , m_defaultPlaybackRate(1.0f)
74     , m_networkState(EMPTY)
75     , m_readyState(DATA_UNAVAILABLE)
76     , m_begun(false)
77     , m_loadedFirstFrame(false)
78     , m_autoplaying(true)
79     , m_currentLoop(0)
80     , m_volume(1.0f)
81     , m_muted(false)
82     , m_paused(true)
83     , m_seeking(false)
84     , m_currentTimeDuringSeek(0)
85     , m_previousProgress(0)
86     , m_previousProgressTime(numeric_limits<double>::max())
87     , m_sentStalledEvent(false)
88     , m_bufferingRate(0)
89     , m_loadNestingLevel(0)
90     , m_terminateLoadBelowNestingLevel(0)
91     , m_pausedInternal(false)
92     , m_inActiveDocument(true)
93     , m_player(0)
94     , m_loadRestrictions(NoLoadRestriction)
95     , m_processingMediaPlayerCallback(0)
96     , m_sendProgressEvents(true)
97 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
98     , m_needWidgetUpdate(false)
99 #endif
100 {
101     document()->registerForDocumentActivationCallbacks(this);
102     document()->registerForMediaVolumeCallbacks(this);
103 }
104
105 HTMLMediaElement::~HTMLMediaElement()
106 {
107     document()->unregisterForDocumentActivationCallbacks(this);
108     document()->unregisterForMediaVolumeCallbacks(this);
109 }
110
111 bool HTMLMediaElement::checkDTD(const Node* newChild)
112 {
113     return newChild->hasTagName(sourceTag) || HTMLElement::checkDTD(newChild);
114 }
115
116 void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls)
117 {
118     HTMLElement::attributeChanged(attr, preserveDecls);
119
120     const QualifiedName& attrName = attr->name();
121     if (attrName == srcAttr) {
122         // 3.14.9.2.
123         // change to src attribute triggers load()
124         if (inDocument() && m_networkState == EMPTY)
125             scheduleLoad();
126     } 
127 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
128     else if (attrName == controlsAttr) {
129         if (!isVideo() && attached() && (controls() != (renderer() != 0))) {
130             detach();
131             attach();
132         }
133         if (renderer())
134             renderer()->updateFromElement();
135     }
136 #endif
137 }
138     
139 bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style)
140 {
141 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
142     UNUSED_PARAM(style);
143     Frame* frame = document()->frame();
144     if (!frame)
145         return false;
146
147     return true;
148 #else
149     return controls() ? HTMLElement::rendererIsNeeded(style) : false;
150 #endif
151 }
152
153 RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
154 {
155 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
156     return new (arena) RenderPartObject(this);
157 #else
158     return new (arena) RenderMedia(this);
159 #endif
160 }
161  
162 void HTMLMediaElement::insertedIntoDocument()
163 {
164     HTMLElement::insertedIntoDocument();
165     if (!src().isEmpty())
166         scheduleLoad();
167 }
168
169 void HTMLMediaElement::removedFromDocument()
170 {
171     if (networkState() != EMPTY) {
172         ExceptionCode ec;
173         pause(ec);
174     }
175     HTMLElement::removedFromDocument();
176 }
177
178 void HTMLMediaElement::attach()
179 {
180     ASSERT(!attached());
181
182 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
183     m_needWidgetUpdate = true;
184 #endif
185
186     HTMLElement::attach();
187
188     if (renderer())
189         renderer()->updateFromElement();
190 }
191
192 void HTMLMediaElement::recalcStyle(StyleChange change)
193 {
194     HTMLElement::recalcStyle(change);
195
196     if (renderer())
197         renderer()->updateFromElement();
198 }
199
200 void HTMLMediaElement::scheduleLoad()
201 {
202     m_loadTimer.startOneShot(0);
203 }
204
205 void HTMLMediaElement::initAndDispatchProgressEvent(const AtomicString& eventName)
206 {
207     if (!m_sendProgressEvents)
208         return;
209
210     bool totalKnown = m_player && m_player->totalBytesKnown();
211     unsigned loaded = m_player ? m_player->bytesLoaded() : 0;
212     unsigned total = m_player ? m_player->totalBytes() : 0;
213     dispatchProgressEvent(eventName, totalKnown, loaded, total);
214     if (renderer())
215         renderer()->updateFromElement();
216 }
217
218 void HTMLMediaElement::dispatchEventAsync(const AtomicString& eventName)
219 {
220     m_asyncEventsToDispatch.append(eventName);
221     if (!m_asyncEventTimer.isActive())                            
222         m_asyncEventTimer.startOneShot(0);
223 }
224
225 void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
226 {
227     ExceptionCode ec;
228     load(ec);
229 }
230
231 void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
232 {
233     Vector<AtomicString> asyncEventsToDispatch;
234     m_asyncEventsToDispatch.swap(asyncEventsToDispatch);
235     unsigned count = asyncEventsToDispatch.size();
236     for (unsigned n = 0; n < count; ++n)
237         dispatchEventForType(asyncEventsToDispatch[n], false, true);
238 }
239
240 static String serializeTimeOffset(float time)
241 {
242     String timeString = String::number(time);
243     // FIXME serialize time offset values properly (format not specified yet)
244     timeString.append("s");
245     return timeString;
246 }
247
248 static float parseTimeOffset(const String& timeString, bool* ok = 0)
249 {
250     const UChar* characters = timeString.characters();
251     unsigned length = timeString.length();
252     
253     if (length && characters[length - 1] == 's')
254         length--;
255     
256     // FIXME parse time offset values (format not specified yet)
257     float val = charactersToFloat(characters, length, ok);
258     return val;
259 }
260
261 float HTMLMediaElement::getTimeOffsetAttribute(const QualifiedName& name, float valueOnError) const
262 {
263     bool ok;
264     String timeString = getAttribute(name);
265     float result = parseTimeOffset(timeString, &ok);
266     if (ok)
267         return result;
268     return valueOnError;
269 }
270
271 void HTMLMediaElement::setTimeOffsetAttribute(const QualifiedName& name, float value)
272 {
273     setAttribute(name, serializeTimeOffset(value));
274 }
275
276 PassRefPtr<MediaError> HTMLMediaElement::error() const 
277 {
278     return m_error;
279 }
280
281 KURL HTMLMediaElement::src() const
282 {
283     return document()->completeURL(getAttribute(srcAttr));
284 }
285
286 void HTMLMediaElement::setSrc(const String& url)
287 {
288     setAttribute(srcAttr, url);
289 }
290
291 String HTMLMediaElement::currentSrc() const
292 {
293     return m_currentSrc;
294 }
295
296 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
297 {
298     return m_networkState;
299 }
300
301 float HTMLMediaElement::bufferingRate()
302 {
303     if (!m_player)
304         return 0;
305     return m_bufferingRate;
306     //return m_player->dataRate();
307 }
308
309 void HTMLMediaElement::load(ExceptionCode& ec)
310 {
311     if ((m_loadRestrictions & RequireUserGestureLoadRestriction) && !processingUserGesture()) {
312         ec = INVALID_STATE_ERR;
313         return;
314     }
315
316     String mediaSrc;
317     String mediaMIMEType;
318
319     // 3.14.9.4. Loading the media resource
320     // 1
321     // if an event generated during load() ends up re-entering load(), terminate previous instances
322     m_loadNestingLevel++;
323     m_terminateLoadBelowNestingLevel = m_loadNestingLevel;
324     
325     m_progressEventTimer.stop();
326     m_sentStalledEvent = false;
327     m_bufferingRate = 0;
328     
329     m_loadTimer.stop();
330     
331     // 2
332     if (m_begun) {
333         m_begun = false;
334         m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
335         if (m_sendProgressEvents)
336             initAndDispatchProgressEvent(eventNames().abortEvent);
337         if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
338             goto end;
339     }
340     
341     // 3
342     m_error = 0;
343     m_loadedFirstFrame = false;
344     m_autoplaying = true;
345
346     // 4
347     setPlaybackRate(defaultPlaybackRate(), ec);
348     
349     // 5
350     if (networkState() != EMPTY) {
351         m_networkState = EMPTY;
352         m_readyState = DATA_UNAVAILABLE;
353         m_paused = true;
354         m_seeking = false;
355         if (m_player) {
356             m_player->pause();
357             m_player->seek(0);
358         }
359         m_currentLoop = 0;
360         dispatchEventForType(eventNames().emptiedEvent, false, true);
361         if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
362             goto end;
363     }
364     
365     // 6
366     mediaSrc = selectMediaURL(mediaMIMEType);
367     if (mediaSrc.isEmpty()) {
368         ec = INVALID_STATE_ERR;
369         goto end;
370     }
371     
372     // 7
373     m_networkState = LOADING;
374     
375     // 8
376     m_currentSrc = mediaSrc;
377
378     // 9
379     m_begun = true;        
380     if (m_sendProgressEvents)
381         dispatchProgressEvent(eventNames().loadstartEvent, false, 0, 0);
382     if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
383         goto end;
384     
385     // 10, 11, 12, 13
386 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
387     m_player.clear();
388     m_player.set(new MediaPlayer(this));
389 #endif
390
391     updateVolume();
392     m_player->load(m_currentSrc, mediaMIMEType);
393     if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
394         goto end;
395     
396     if (renderer())
397         renderer()->updateFromElement();
398     
399     // 14
400     if (m_sendProgressEvents) {
401         m_previousProgressTime = WTF::currentTime();
402         m_previousProgress = 0;
403         if (m_begun)
404             // 350ms is not magic, it is in the spec!
405             m_progressEventTimer.startRepeating(0.350);
406     }
407
408 end:
409     ASSERT(m_loadNestingLevel);
410     m_loadNestingLevel--;
411 }
412
413
414 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
415 {
416     if (!m_begun)
417         return;
418     
419     beginProcessingMediaPlayerCallback();
420     setNetworkState(m_player->networkState());
421     endProcessingMediaPlayerCallback();
422 }
423
424 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
425 {
426     if (m_networkState == EMPTY) {
427         // just update the cached state and leave, we can't do anything 
428         m_networkState = EMPTY;
429         return;
430     }
431     
432     m_terminateLoadBelowNestingLevel = m_loadNestingLevel;
433     
434     // 3.14.9.4. Loading the media resource
435     // 14
436     if (state == MediaPlayer::LoadFailed) {
437         //delete m_player;
438         //m_player = 0;
439         // FIXME better error handling
440         m_error = MediaError::create(MediaError::MEDIA_ERR_NETWORK);
441         m_begun = false;
442         m_progressEventTimer.stop();
443         m_bufferingRate = 0;
444         
445         initAndDispatchProgressEvent(eventNames().errorEvent); 
446         if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
447             return;
448         
449         m_networkState = EMPTY;
450
451         if (isVideo())
452             static_cast<HTMLVideoElement*>(this)->updatePosterImage();
453
454         dispatchEventForType(eventNames().emptiedEvent, false, true);
455         return;
456     }
457     
458     if (state >= MediaPlayer::Loading && m_networkState < LOADING)
459         m_networkState = LOADING;
460     
461     if (state >= MediaPlayer::LoadedMetaData && m_networkState < LOADED_METADATA) {
462         m_player->seek(effectiveStart());
463         m_networkState = LOADED_METADATA;
464         
465         dispatchEventForType(eventNames().durationchangeEvent, false, true);
466         if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
467             return;
468         
469         dispatchEventForType(eventNames().loadedmetadataEvent, false, true);
470         if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
471             return;
472     }
473     
474     if (state >= MediaPlayer::LoadedFirstFrame && m_networkState < LOADED_FIRST_FRAME) {
475         m_networkState = LOADED_FIRST_FRAME;
476         
477         setReadyState(CAN_SHOW_CURRENT_FRAME);
478         
479         if (isVideo())
480             static_cast<HTMLVideoElement*>(this)->updatePosterImage();
481
482         if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
483             return;
484         
485         m_loadedFirstFrame = true;
486         if (renderer()) {
487             ASSERT(!renderer()->isImage());
488             static_cast<RenderVideo*>(renderer())->videoSizeChanged();
489         }
490         
491         dispatchEventForType(eventNames().loadedfirstframeEvent, false, true);
492         if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
493             return;
494         
495         dispatchEventForType(eventNames().canshowcurrentframeEvent, false, true);
496         if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
497             return;
498     }
499     
500     // 15
501     if (state == MediaPlayer::Loaded && m_networkState < LOADED) {
502         m_begun = false;
503         m_networkState = LOADED;
504         m_progressEventTimer.stop();
505         m_bufferingRate = 0;
506         initAndDispatchProgressEvent(eventNames().loadEvent); 
507     }
508 }
509
510 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
511 {
512     beginProcessingMediaPlayerCallback();
513
514     MediaPlayer::ReadyState state = m_player->readyState();
515     setReadyState((ReadyState)state);
516
517     endProcessingMediaPlayerCallback();
518 }
519
520 void HTMLMediaElement::setReadyState(ReadyState state)
521 {
522     // 3.14.9.6. The ready states
523     if (m_readyState == state)
524         return;
525     
526     bool wasActivelyPlaying = activelyPlaying();
527     m_readyState = state;
528     
529     if (state >= CAN_PLAY)
530         m_seeking = false;
531     
532     if (networkState() == EMPTY)
533         return;
534     
535     if (state == DATA_UNAVAILABLE) {
536         dispatchEventForType(eventNames().dataunavailableEvent, false, true);
537         if (wasActivelyPlaying) {
538             dispatchEventForType(eventNames().timeupdateEvent, false, true);
539             dispatchEventForType(eventNames().waitingEvent, false, true);
540         }
541     } else if (state == CAN_SHOW_CURRENT_FRAME) {
542         if (m_loadedFirstFrame)
543             dispatchEventForType(eventNames().canshowcurrentframeEvent, false, true);
544         if (wasActivelyPlaying) {
545             dispatchEventForType(eventNames().timeupdateEvent, false, true);
546             dispatchEventForType(eventNames().waitingEvent, false, true);
547         }
548     } else if (state == CAN_PLAY) {
549         dispatchEventForType(eventNames().canplayEvent, false, true);
550     } else if (state == CAN_PLAY_THROUGH) {
551         dispatchEventForType(eventNames().canplaythroughEvent, false, true);
552         if (m_autoplaying && m_paused && autoplay()) {
553             m_paused = false;
554             dispatchEventForType(eventNames().playEvent, false, true);
555         }
556     }
557     updatePlayState();
558 }
559
560 void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
561 {
562     ASSERT(m_player);
563     unsigned progress = m_player->bytesLoaded();
564     double time = WTF::currentTime();
565     double timedelta = time - m_previousProgressTime;
566     if (timedelta)
567         m_bufferingRate = (float)(0.8 * m_bufferingRate + 0.2 * ((float)(progress - m_previousProgress)) / timedelta);
568     
569     if (progress == m_previousProgress) {
570         if (timedelta > 3.0 && !m_sentStalledEvent) {
571             m_bufferingRate = 0;
572             initAndDispatchProgressEvent(eventNames().stalledEvent);
573             m_sentStalledEvent = true;
574         }
575     } else {
576         initAndDispatchProgressEvent(eventNames().progressEvent);
577         m_previousProgress = progress;
578         m_previousProgressTime = time;
579         m_sentStalledEvent = false;
580     }
581 }
582
583 void HTMLMediaElement::seek(float time, ExceptionCode& ec)
584 {
585     // 3.14.9.8. Seeking
586     // 1
587     if (networkState() < LOADED_METADATA) {
588         ec = INVALID_STATE_ERR;
589         return;
590     }
591     
592     // 2
593     float minTime;
594     if (currentLoop() == 0)
595         minTime = effectiveStart();
596     else
597         minTime = effectiveLoopStart();
598  
599     // 3
600     float maxTime = currentLoop() == playCount() - 1 ? effectiveEnd() : effectiveLoopEnd();
601     
602     // 4
603     time = min(time, maxTime);
604     
605     // 5
606     time = max(time, minTime);
607     
608     // 6
609     RefPtr<TimeRanges> seekableRanges = seekable();
610     if (!seekableRanges->contain(time)) {
611         ec = INDEX_SIZE_ERR;
612         return;
613     }
614     
615     // 7
616     m_currentTimeDuringSeek = time;
617
618     // 8
619     m_seeking = true;
620     
621     // 9
622     dispatchEventForType(eventNames().timeupdateEvent, false, true);
623     
624     // 10
625     // As soon as the user agent has established whether or not the media data for the new playback position is available, 
626     // and, if it is, decoded enough data to play back that position, the seeking DOM attribute must be set to false.
627     if (m_player) {
628         m_player->setEndTime(maxTime);
629         m_player->seek(time);
630     }
631 }
632
633 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
634 {
635     return m_readyState;
636 }
637
638 bool HTMLMediaElement::seeking() const
639 {
640     return m_seeking;
641 }
642
643 // playback state
644 float HTMLMediaElement::currentTime() const
645 {
646     if (!m_player)
647         return 0;
648     if (m_seeking)
649         return m_currentTimeDuringSeek;
650     return m_player->currentTime();
651 }
652
653 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
654 {
655     seek(time, ec);
656 }
657
658 float HTMLMediaElement::duration() const
659 {
660     return m_player ? m_player->duration() : 0;
661 }
662
663 bool HTMLMediaElement::paused() const
664 {
665     return m_paused;
666 }
667
668 float HTMLMediaElement::defaultPlaybackRate() const
669 {
670     return m_defaultPlaybackRate;
671 }
672
673 void HTMLMediaElement::setDefaultPlaybackRate(float rate, ExceptionCode& ec)
674 {
675     if (rate == 0.0f) {
676         ec = NOT_SUPPORTED_ERR;
677         return;
678     }
679     if (m_defaultPlaybackRate != rate) {
680         m_defaultPlaybackRate = rate;
681         dispatchEventAsync(eventNames().ratechangeEvent);
682     }
683 }
684
685 float HTMLMediaElement::playbackRate() const
686 {
687     return m_player ? m_player->rate() : 0;
688 }
689
690 void HTMLMediaElement::setPlaybackRate(float rate, ExceptionCode& ec)
691 {
692     if (rate == 0.0f) {
693         ec = NOT_SUPPORTED_ERR;
694         return;
695     }
696     if (m_player && m_player->rate() != rate) {
697         m_player->setRate(rate);
698         dispatchEventAsync(eventNames().ratechangeEvent);
699     }
700 }
701
702 bool HTMLMediaElement::ended() const
703 {
704     return endedPlayback();
705 }
706
707 bool HTMLMediaElement::autoplay() const
708 {
709     return hasAttribute(autoplayAttr);
710 }
711
712 void HTMLMediaElement::setAutoplay(bool b)
713 {
714     setBooleanAttribute(autoplayAttr, b);
715 }
716
717 void HTMLMediaElement::play(ExceptionCode& ec)
718 {
719     // 3.14.9.7. Playing the media resource
720     if (!m_player || networkState() == EMPTY) {
721         ec = 0;
722         load(ec);
723         if (ec)
724             return;
725     }
726     ExceptionCode unused;
727     if (endedPlayback()) {
728         m_currentLoop = 0;
729         seek(effectiveStart(), unused);
730     }
731     setPlaybackRate(defaultPlaybackRate(), unused);
732     
733     if (m_paused) {
734         m_paused = false;
735         dispatchEventAsync(eventNames().playEvent);
736     }
737
738     m_autoplaying = false;
739
740     updatePlayState();
741 }
742
743 void HTMLMediaElement::pause(ExceptionCode& ec)
744 {
745     // 3.14.9.7. Playing the media resource
746     if (!m_player || networkState() == EMPTY) {
747         ec = 0;
748         load(ec);
749         if (ec)
750             return;
751     }
752
753     if (!m_paused) {
754         m_paused = true;
755         dispatchEventAsync(eventNames().timeupdateEvent);
756         dispatchEventAsync(eventNames().pauseEvent);
757     }
758
759     m_autoplaying = false;
760     
761     updatePlayState();
762 }
763
764 unsigned HTMLMediaElement::playCount() const
765 {
766     bool ok;
767     unsigned count = getAttribute(playcountAttr).string().toUInt(&ok);
768     return (count > 0 && ok) ? count : 1; 
769 }
770
771 void HTMLMediaElement::setPlayCount(unsigned count, ExceptionCode& ec)
772 {
773     if (!count) {
774         ec = INDEX_SIZE_ERR;
775         return;
776     }
777     setAttribute(playcountAttr, String::number(count));
778     checkIfSeekNeeded();
779 }
780
781 float HTMLMediaElement::start() const 
782
783     return getTimeOffsetAttribute(startAttr, 0); 
784 }
785
786 void HTMLMediaElement::setStart(float time) 
787
788     setTimeOffsetAttribute(startAttr, time); 
789     checkIfSeekNeeded();
790 }
791
792 float HTMLMediaElement::end() const 
793
794     return getTimeOffsetAttribute(endAttr, std::numeric_limits<float>::infinity()); 
795 }
796
797 void HTMLMediaElement::setEnd(float time) 
798
799     setTimeOffsetAttribute(endAttr, time); 
800     checkIfSeekNeeded();
801 }
802
803 float HTMLMediaElement::loopStart() const 
804
805     return getTimeOffsetAttribute(loopstartAttr, start()); 
806 }
807
808 void HTMLMediaElement::setLoopStart(float time) 
809 {
810     setTimeOffsetAttribute(loopstartAttr, time); 
811     checkIfSeekNeeded();
812 }
813
814 float HTMLMediaElement::loopEnd() const 
815
816     return getTimeOffsetAttribute(loopendAttr, end()); 
817 }
818
819 void HTMLMediaElement::setLoopEnd(float time) 
820
821     setTimeOffsetAttribute(loopendAttr, time); 
822     checkIfSeekNeeded();
823 }
824
825 unsigned HTMLMediaElement::currentLoop() const
826 {
827     return m_currentLoop;
828 }
829
830 void HTMLMediaElement::setCurrentLoop(unsigned currentLoop)
831 {
832     m_currentLoop = currentLoop;
833 }
834
835 bool HTMLMediaElement::controls() const
836 {
837     Frame* frame = document()->frame();
838
839     // always show controls when scripting is disabled
840     if (frame && !frame->script()->isEnabled())
841         return true;
842
843     return hasAttribute(controlsAttr);
844 }
845
846 void HTMLMediaElement::setControls(bool b)
847 {
848     setBooleanAttribute(controlsAttr, b);
849 }
850
851 float HTMLMediaElement::volume() const
852 {
853     return m_volume;
854 }
855
856 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
857 {
858     if (vol < 0.0f || vol > 1.0f) {
859         ec = INDEX_SIZE_ERR;
860         return;
861     }
862     
863     if (m_volume != vol) {
864         m_volume = vol;
865         updateVolume();
866         dispatchEventAsync(eventNames().volumechangeEvent);
867     }
868 }
869
870 bool HTMLMediaElement::muted() const
871 {
872     return m_muted;
873 }
874
875 void HTMLMediaElement::setMuted(bool muted)
876 {
877     if (m_muted != muted) {
878         m_muted = muted;
879         updateVolume();
880         dispatchEventAsync(eventNames().volumechangeEvent);
881     }
882 }
883
884 void HTMLMediaElement::togglePlayState(ExceptionCode& ec)
885 {
886     if (canPlay())
887         play(ec);
888     else 
889         pause(ec);
890 }
891
892 void HTMLMediaElement::beginScrubbing()
893 {
894     if (!paused()) {
895         if (ended()) {
896             // because a media element stays in non-paused state when it reaches end, playback resumes 
897             //  when the slider is dragged from the end to another position unless we pause first. do 
898             //  a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes
899             ExceptionCode ec;
900             pause(ec);
901         } else {
902             // not at the end but we still want to pause playback so the media engine doesn't try to
903             //  continue playing during scrubbing. pause without generating an event as we will 
904             //  unpause after scrubbing finishes
905             setPausedInternal(true);
906         }
907     }
908 }
909
910 void HTMLMediaElement::endScrubbing()
911 {
912     if (m_pausedInternal)
913         setPausedInternal(false);
914 }
915
916 bool HTMLMediaElement::canPlay() const
917 {
918     return paused() || ended() || networkState() < LOADED_METADATA;
919 }
920
921 String HTMLMediaElement::selectMediaURL(String& mediaMIMEType)
922 {
923     // 3.14.9.2. Location of the media resource
924     String mediaSrc = getAttribute(srcAttr);
925     if (mediaSrc.isEmpty()) {
926         for (Node* n = firstChild(); n; n = n->nextSibling()) {
927             if (n->hasTagName(sourceTag)) {
928                 HTMLSourceElement* source = static_cast<HTMLSourceElement*>(n);
929                 if (!source->hasAttribute(srcAttr))
930                     continue; 
931                 if (source->hasAttribute(mediaAttr)) {
932                     MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
933                     RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
934                     if (!screenEval.eval(media.get()))
935                         continue;
936                 }
937                 if (source->hasAttribute(typeAttr)) {
938                     ContentType contentType(source->type());
939                     if (!MediaPlayer::supportsType(contentType.type(), contentType.parameter("codecs")))
940                         continue;
941
942                     // return type with all parameters in place so the media engine can use them
943                     mediaMIMEType = contentType.raw();
944                 }
945                 mediaSrc = source->src().string();
946                 break;
947             }
948         }
949     }
950     if (!mediaSrc.isEmpty())
951         mediaSrc = document()->completeURL(mediaSrc).string();
952     return mediaSrc;
953 }
954
955 void HTMLMediaElement::checkIfSeekNeeded()
956 {
957     // 3.14.9.5. Offsets into the media resource
958     // 1
959     if (playCount() <= m_currentLoop)
960         m_currentLoop = playCount() - 1;
961     
962     // 2
963     if (networkState() <= LOADING)
964         return;
965     
966     // 3
967     ExceptionCode ec;
968     float time = currentTime();
969     if (!m_currentLoop && time < effectiveStart())
970         seek(effectiveStart(), ec);
971
972     // 4
973     if (m_currentLoop && time < effectiveLoopStart())
974         seek(effectiveLoopStart(), ec);
975         
976     // 5
977     if (m_currentLoop < playCount() - 1 && time > effectiveLoopEnd()) {
978         seek(effectiveLoopStart(), ec);
979         m_currentLoop++;
980     }
981     
982     // 6
983     if (m_currentLoop == playCount() - 1 && time > effectiveEnd())
984         seek(effectiveEnd(), ec);
985
986     updatePlayState();
987 }
988
989 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
990 {
991     beginProcessingMediaPlayerCallback();
992
993     if (readyState() >= CAN_PLAY)
994         m_seeking = false;
995     
996     float now = currentTime();
997     if (m_currentLoop < playCount() - 1 && now >= effectiveLoopEnd()) {
998         ExceptionCode ec;
999         seek(effectiveLoopStart(), ec);
1000         m_currentLoop++;
1001         dispatchEventForType(eventNames().timeupdateEvent, false, true);
1002     }
1003     
1004     if (m_currentLoop == playCount() - 1 && now >= effectiveEnd()) {
1005         dispatchEventForType(eventNames().timeupdateEvent, false, true);
1006         dispatchEventForType(eventNames().endedEvent, false, true);
1007     }
1008
1009     updatePlayState();
1010
1011     endProcessingMediaPlayerCallback();
1012 }
1013
1014 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
1015 {
1016     beginProcessingMediaPlayerCallback();
1017     if (renderer())
1018         renderer()->repaint();
1019     endProcessingMediaPlayerCallback();
1020 }
1021
1022 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
1023 {
1024     beginProcessingMediaPlayerCallback();
1025     updateVolume();
1026     endProcessingMediaPlayerCallback();
1027 }
1028
1029 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
1030 {
1031     // FIXME real ranges support
1032     if (!m_player || !m_player->maxTimeBuffered())
1033         return TimeRanges::create();
1034     return TimeRanges::create(0, m_player->maxTimeBuffered());
1035 }
1036
1037 PassRefPtr<TimeRanges> HTMLMediaElement::played() const
1038 {
1039     // FIXME track played
1040     return TimeRanges::create();
1041 }
1042
1043 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
1044 {
1045     // FIXME real ranges support
1046     if (!m_player || !m_player->maxTimeSeekable())
1047         return TimeRanges::create();
1048     return TimeRanges::create(0, m_player->maxTimeSeekable());
1049 }
1050
1051 float HTMLMediaElement::effectiveStart() const
1052 {
1053     if (!m_player)
1054         return 0;
1055     return min(start(), m_player->duration());
1056 }
1057
1058 float HTMLMediaElement::effectiveEnd() const
1059 {
1060     if (!m_player)
1061         return 0;
1062     return min(max(end(), max(start(), loopStart())), m_player->duration());
1063 }
1064
1065 float HTMLMediaElement::effectiveLoopStart() const
1066 {
1067     if (!m_player)
1068         return 0;
1069     return min(loopStart(), m_player->duration());
1070 }
1071
1072 float HTMLMediaElement::effectiveLoopEnd() const
1073 {
1074     if (!m_player)
1075         return 0;
1076     return min(max(start(), max(loopStart(), loopEnd())), m_player->duration());
1077 }
1078
1079 bool HTMLMediaElement::activelyPlaying() const
1080 {
1081     return !paused() && readyState() >= CAN_PLAY && !endedPlayback(); // && !stoppedDueToErrors() && !pausedForUserInteraction();
1082 }
1083
1084 bool HTMLMediaElement::endedPlayback() const
1085 {
1086     return networkState() >= LOADED_METADATA && currentTime() >= effectiveEnd() && currentLoop() == playCount() - 1;
1087 }
1088     
1089 void HTMLMediaElement::updateVolume()
1090 {
1091     if (!m_player)
1092         return;
1093
1094     // Avoid recursion when the player reports volume changes.
1095     if (!processingMediaPlayerCallback()) {
1096         Page* page = document()->page();
1097         float volumeMultiplier = page ? page->mediaVolume() : 1;
1098     
1099         m_player->setVolume(m_muted ? 0 : m_volume * volumeMultiplier);
1100     }
1101     
1102     if (renderer())
1103         renderer()->updateFromElement();
1104 }
1105
1106 void HTMLMediaElement::updatePlayState()
1107 {
1108     if (!m_player)
1109         return;
1110     
1111     if (m_pausedInternal) {
1112         if (!m_player->paused())
1113             m_player->pause();
1114         return;
1115     }
1116     
1117     m_player->setEndTime(currentLoop() == playCount() - 1 ? effectiveEnd() : effectiveLoopEnd());
1118
1119     bool shouldBePlaying = activelyPlaying() && currentTime() < effectiveEnd();
1120     if (shouldBePlaying && m_player->paused())
1121         m_player->play();
1122     else if (!shouldBePlaying && !m_player->paused())
1123         m_player->pause();
1124     
1125     if (renderer())
1126         renderer()->updateFromElement();
1127 }
1128     
1129 void HTMLMediaElement::setPausedInternal(bool b)
1130 {
1131     m_pausedInternal = b;
1132     updatePlayState();
1133 }
1134
1135 void HTMLMediaElement::documentWillBecomeInactive()
1136 {
1137     // 3.14.9.4. Loading the media resource
1138     // 14
1139     if (m_begun) {
1140         // For simplicity cancel the incomplete load by deleting the player
1141         m_player.clear();
1142         m_progressEventTimer.stop();
1143
1144         m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
1145         m_begun = false;
1146         initAndDispatchProgressEvent(eventNames().abortEvent);
1147         if (m_networkState >= LOADING) {
1148             m_networkState = EMPTY;
1149             m_readyState = DATA_UNAVAILABLE;
1150             dispatchEventForType(eventNames().emptiedEvent, false, true);
1151         }
1152     }
1153     m_inActiveDocument = false;
1154     // Stop the playback without generating events
1155     setPausedInternal(true);
1156
1157     if (renderer())
1158         renderer()->updateFromElement();
1159 }
1160
1161 void HTMLMediaElement::documentDidBecomeActive()
1162 {
1163     m_inActiveDocument = true;
1164     setPausedInternal(false);
1165
1166     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
1167         // Restart the load if it was aborted in the middle by moving the document to the page cache.
1168         // This behavior is not specified but it seems like a sensible thing to do.
1169         ExceptionCode ec;
1170         load(ec);
1171     }
1172         
1173     if (renderer())
1174         renderer()->updateFromElement();
1175 }
1176
1177 void HTMLMediaElement::mediaVolumeDidChange()
1178 {
1179     updateVolume();
1180 }
1181
1182 void HTMLMediaElement::defaultEventHandler(Event* event)
1183 {
1184 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1185     RenderObject* r = renderer();
1186     if (!r || !r->isWidget())
1187         return;
1188
1189     Widget* widget = static_cast<RenderWidget*>(r)->widget();
1190     if (widget)
1191         widget->handleEvent(event);
1192 #else
1193     if (renderer() && renderer()->isMedia())
1194         static_cast<RenderMedia*>(renderer())->forwardEvent(event);
1195     if (event->defaultHandled())
1196         return;
1197     HTMLElement::defaultEventHandler(event);
1198 #endif
1199 }
1200
1201 bool HTMLMediaElement::processingUserGesture() const
1202 {
1203     Frame* frame = document()->frame();
1204     FrameLoader* loader = frame ? frame->loader() : 0;
1205
1206     // return 'true' for safety if we don't know the answer 
1207     return loader ? loader->userGestureHint() : true;
1208 }
1209
1210 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1211 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
1212 {
1213     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
1214         ExceptionCode ec;
1215         togglePlayState(ec);
1216          return;
1217     }
1218
1219     if (m_player)
1220         m_player->deliverNotification(notification);
1221 }
1222
1223 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
1224 {
1225     if (m_player)
1226         m_player->setMediaPlayerProxy(proxy);
1227 }
1228
1229 String HTMLMediaElement::initialURL()
1230 {
1231     String ignoredType;
1232     String initialSrc = selectMediaURL(ignoredType);
1233     m_currentSrc = initialSrc;
1234     return initialSrc;
1235 }
1236
1237 void HTMLMediaElement::finishParsingChildren()
1238 {
1239     HTMLElement::finishParsingChildren();
1240     if (!m_player)
1241         m_player.set(new MediaPlayer(this));
1242     
1243     document()->updateRendering();
1244     if (m_needWidgetUpdate && renderer())
1245         static_cast<RenderPartObject*>(renderer())->updateWidget(true);
1246 }
1247 #endif
1248
1249 }
1250
1251 #endif