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