120
150
renderer()->updateFromElement();
155
void HTMLMediaElement::parseMappedAttribute(MappedAttribute* attr)
157
const QualifiedName& attrName = attr->name();
159
if (attrName == autobufferAttr) {
161
m_player->setAutobuffer(!attr->isNull());
162
} else if (attrName == onabortAttr)
163
setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
164
else if (attrName == oncanplayAttr)
165
setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, attr));
166
else if (attrName == oncanplaythroughAttr)
167
setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, attr));
168
else if (attrName == ondurationchangeAttr)
169
setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, attr));
170
else if (attrName == onemptiedAttr)
171
setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, attr));
172
else if (attrName == onendedAttr)
173
setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, attr));
174
else if (attrName == onerrorAttr)
175
setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr));
176
else if (attrName == onloadAttr)
177
setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
178
else if (attrName == onloadeddataAttr)
179
setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
180
else if (attrName == onloadedmetadataAttr)
181
setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
182
else if (attrName == onloadendAttr)
183
setAttributeEventListener(eventNames().loadendEvent, createAttributeEventListener(this, attr));
184
else if (attrName == onloadstartAttr)
185
setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
186
else if (attrName == onpauseAttr)
187
setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, attr));
188
else if (attrName == onplayAttr)
189
setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, attr));
190
else if (attrName == onplayingAttr)
191
setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, attr));
192
else if (attrName == onprogressAttr)
193
setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, attr));
194
else if (attrName == onratechangeAttr)
195
setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, attr));
196
else if (attrName == onseekedAttr)
197
setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, attr));
198
else if (attrName == onseekingAttr)
199
setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, attr));
200
else if (attrName == onstalledAttr)
201
setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, attr));
202
else if (attrName == onsuspendAttr)
203
setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, attr));
204
else if (attrName == ontimeupdateAttr)
205
setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, attr));
206
else if (attrName == onvolumechangeAttr)
207
setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, attr));
208
else if (attrName == onwaitingAttr)
209
setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, attr));
211
HTMLElement::parseMappedAttribute(attr);
124
214
bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style)
216
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
218
Frame* frame = document()->frame();
126
224
return controls() ? HTMLElement::rendererIsNeeded(style) : false;
129
228
RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
230
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
231
return new (arena) RenderPartObject(this);
131
233
return new (arena) RenderMedia(this);
134
237
void HTMLMediaElement::insertedIntoDocument()
136
239
HTMLElement::insertedIntoDocument();
137
if (!src().isEmpty())
240
if (!src().isEmpty() && m_networkState == NETWORK_EMPTY)
141
244
void HTMLMediaElement::removedFromDocument()
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.
246
if (m_networkState > NETWORK_EMPTY)
147
248
HTMLElement::removedFromDocument();
263
394
return m_networkState;
266
float HTMLMediaElement::bufferingRate()
397
String HTMLMediaElement::canPlayType(const String& mimeType) const
270
return m_bufferingRate;
271
//return m_player->dataRate();
399
MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType));
405
case MediaPlayer::IsNotSupported:
408
case MediaPlayer::MayBeSupported:
411
case MediaPlayer::IsSupported:
412
canPlay = "probably";
274
419
void HTMLMediaElement::load(ExceptionCode& ec)
277
Frame* frame = document()->frame();
278
FrameLoader* loader = frame ? frame->loader() : 0;
280
// 3.14.9.4. Loading the media resource
282
// if an event generated during load() ends up re-entering load(), terminate previous instances
283
m_loadNestingLevel++;
284
m_terminateLoadBelowNestingLevel = m_loadNestingLevel;
286
m_progressEventTimer.stop();
421
if (m_restrictions & RequireUserGestureForLoadRestriction && !processingUserGesture())
422
ec = INVALID_STATE_ERR;
429
void HTMLMediaElement::prepareForLoad()
431
// Perform the cleanup required for the resource load algorithm to run.
432
stopPeriodicTimers();
287
434
m_sentStalledEvent = false;
435
m_haveFiredLoadedData = false;
437
// 2 - Abort any already-running instance of the resource selection algorithm for this element.
438
m_currentSourceNode = 0;
440
// 3 - If there are any tasks from the media element's media element event task source in
441
// one of the task queues, then remove those tasks.
442
cancelPendingEventsAndCallbacks();
445
void HTMLMediaElement::loadInternal()
447
// 1 - If the load() method for this element is already being invoked, then abort these steps.
448
if (m_processingLoad)
450
m_processingLoad = true;
452
// Steps 2 and 3 were done in prepareForLoad()
454
// 4 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, set
455
// the error attribute to a new MediaError object whose code attribute is set to
456
// MEDIA_ERR_ABORTED, fire a progress event called abort at the media element, in the
457
// context of the fetching process that is in progress for the element, and fire a progress
458
// event called loadend at the media element, in the context of the same fetching process.
459
if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE) {
295
460
m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
296
initAndDispatchProgressEvent(eventNames().abortEvent);
297
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
462
// fire synchronous 'abort' and 'loadend'
463
bool totalKnown = m_player && m_player->totalBytesKnown();
464
unsigned loaded = m_player ? m_player->bytesLoaded() : 0;
465
unsigned total = m_player ? m_player->totalBytes() : 0;
466
dispatchEvent(ProgressEvent::create(eventNames().abortEvent, totalKnown, loaded, total));
467
dispatchEvent(ProgressEvent::create(eventNames().loadendEvent, totalKnown, loaded, total));
303
m_loadedFirstFrame = false;
304
472
m_autoplaying = true;
307
setPlaybackRate(defaultPlaybackRate(), ec);
310
if (networkState() != EMPTY) {
311
m_networkState = EMPTY;
312
m_readyState = DATA_UNAVAILABLE;
473
m_playedTimeRanges = TimeRanges::create();
477
setPlaybackRate(defaultPlaybackRate());
480
if (m_networkState != NETWORK_EMPTY) {
481
m_networkState = NETWORK_EMPTY;
482
m_readyState = HAVE_NOTHING;
314
484
m_seeking = false;
316
486
m_player->pause();
317
488
m_player->seek(0);
320
dispatchEventForType(eventNames().emptiedEvent, false, true);
321
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
326
mediaSrc = pickMedia();
327
if (mediaSrc.isEmpty()) {
328
ec = INVALID_STATE_ERR;
332
// don't allow remote to local urls
333
if (!loader || !loader->canLoad(KURL(KURL(), mediaSrc), String(), document())) {
334
FrameLoader::reportLocalLoadFailed(frame, mediaSrc);
336
ec = INVALID_STATE_ERR;
341
m_networkState = LOADING;
344
m_currentSrc = mediaSrc;
348
dispatchProgressEvent(eventNames().loadstartEvent, false, 0, 0);
349
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
490
dispatchEvent(Event::create(eventNames().emptiedEvent, false, true));
493
selectMediaResource();
494
m_processingLoad = false;
497
void HTMLMediaElement::selectMediaResource()
499
// 1 - If the media element has neither a src attribute nor any source element children, run these substeps
500
String mediaSrc = getAttribute(srcAttr);
501
if (!mediaSrc && !havePotentialSourceChild()) {
502
m_loadState = WaitingForSource;
504
// 1 - Set the networkState to NETWORK_NO_SOURCE
505
m_networkState = NETWORK_NO_SOURCE;
507
// 2 - While the media element has neither a src attribute nor any source element children,
508
// wait. (This steps might wait forever.)
510
m_delayingTheLoadEvent = false;
515
m_delayingTheLoadEvent = true;
518
m_networkState = NETWORK_LOADING;
521
scheduleProgressEvent(eventNames().loadstartEvent);
523
// 5 - If the media element has a src attribute, then run these substeps
524
ContentType contentType("");
525
if (!mediaSrc.isEmpty()) {
526
KURL mediaURL = document()->completeURL(mediaSrc);
527
if (isSafeToLoadURL(mediaURL, Complain)) {
528
m_loadState = LoadingFromSrcAttr;
529
loadResource(mediaURL, contentType);
536
// Otherwise, the source elements will be used
537
m_currentSourceNode = 0;
538
loadNextSourceChild();
541
void HTMLMediaElement::loadNextSourceChild()
543
ContentType contentType("");
544
KURL mediaURL = selectNextSourceChild(&contentType, Complain);
545
if (!mediaURL.isValid()) {
546
// It seems wrong to fail silently when we give up because no suitable <source>
547
// element can be found and set the error attribute if the element's 'src' attribute
548
// fails, but that is what the spec says.
552
m_loadState = LoadingFromSourceElement;
553
loadResource(mediaURL, contentType);
556
void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
558
ASSERT(isSafeToLoadURL(url, Complain));
560
// The resource fetch algorithm
561
m_networkState = NETWORK_LOADING;
565
if (m_sendProgressEvents)
566
startProgressEventTimer();
568
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
353
569
m_player.clear();
354
570
m_player.set(new MediaPlayer(this));
573
m_player.set(new MediaPlayer(this));
576
m_player->setPreservesPitch(m_webkitPreservesPitch);
356
m_player->load(m_currentSrc);
357
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
579
m_player->load(m_currentSrc, contentType);
361
582
renderer()->updateFromElement();
585
bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
587
Frame* frame = document()->frame();
588
FrameLoader* loader = frame ? frame->loader() : 0;
590
// don't allow remote to local urls, and check with the frame loader client.
591
if (!loader || !loader->canLoad(url, String(), document()) || !loader->client()->shouldLoadMediaElementURL(url)) {
592
if (actionIfInvalid == Complain)
593
FrameLoader::reportLocalLoadFailed(frame, url.string());
364
m_previousProgressTime = WebCore::currentTime();
600
void HTMLMediaElement::startProgressEventTimer()
602
if (m_progressEventTimer.isActive())
605
m_previousProgressTime = WTF::currentTime();
365
606
m_previousProgress = 0;
367
// 350ms is not magic, it is in the spec!
368
m_progressEventTimer.startRepeating(0.350);
370
ASSERT(m_loadNestingLevel);
371
m_loadNestingLevel--;
607
// 350ms is not magic, it is in the spec!
608
m_progressEventTimer.startRepeating(0.350);
611
void HTMLMediaElement::noneSupported()
613
stopPeriodicTimers();
614
m_loadState = WaitingForSource;
615
m_currentSourceNode = 0;
617
// 4 - Reaching this step indicates that either the URL failed to resolve, or the media
618
// resource failed to load. Set the error attribute to a new MediaError object whose
619
// code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
620
m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
622
// 5 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
623
m_networkState = NETWORK_NO_SOURCE;
625
// 6 - Queue a task to fire a progress event called error at the media element, in
626
// the context of the fetching process that was used to try to obtain the media
627
// resource in the resource fetch algorithm.
628
scheduleProgressEvent(eventNames().errorEvent);
630
// 7 - Queue a task to fire a progress event called loadend at the media element, in
631
// the context of the fetching process that was used to try to obtain the media
632
// resource in the resource fetch algorithm.
633
scheduleProgressEvent(eventNames().loadendEvent);
635
// 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
636
m_delayingTheLoadEvent = false;
638
// 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
641
static_cast<HTMLVideoElement*>(this)->updatePosterImage();
643
renderer()->updateFromElement();
646
void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
648
// 1 - The user agent should cancel the fetching process.
649
stopPeriodicTimers();
650
m_loadState = WaitingForSource;
652
// 2 - Set the error attribute to a new MediaError object whose code attribute is
653
// set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
656
// 3 - Queue a task to fire a progress event called error at the media element, in
657
// the context of the fetching process started by this instance of this algorithm.
658
scheduleProgressEvent(eventNames().errorEvent);
660
// 4 - Queue a task to fire a progress event called loadend at the media element, in
661
// the context of the fetching process started by this instance of this algorithm.
662
scheduleProgressEvent(eventNames().loadendEvent);
664
// 5 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
665
// task to fire a simple event called emptied at the element.
666
m_networkState = NETWORK_EMPTY;
667
scheduleEvent(eventNames().emptiedEvent);
669
// 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
670
m_delayingTheLoadEvent = false;
672
// 7 - Abort the overall resource selection algorithm.
673
m_currentSourceNode = 0;
676
void HTMLMediaElement::cancelPendingEventsAndCallbacks()
678
m_pendingEvents.clear();
680
for (Node* node = firstChild(); node; node = node->nextSibling()) {
681
if (node->hasTagName(sourceTag))
682
static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
374
686
void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
376
if (!m_begun || m_networkState == EMPTY)
379
m_terminateLoadBelowNestingLevel = m_loadNestingLevel;
381
MediaPlayer::NetworkState state = m_player->networkState();
383
// 3.14.9.4. Loading the media resource
385
if (state == MediaPlayer::LoadFailed) {
388
// FIXME better error handling
389
m_error = MediaError::create(MediaError::MEDIA_ERR_NETWORK);
391
m_progressEventTimer.stop();
394
initAndDispatchProgressEvent(eventNames().errorEvent);
395
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
398
m_networkState = EMPTY;
401
static_cast<HTMLVideoElement*>(this)->updatePosterImage();
403
dispatchEventForType(eventNames().emptiedEvent, false, true);
407
if (state >= MediaPlayer::Loading && m_networkState < LOADING)
408
m_networkState = LOADING;
410
if (state >= MediaPlayer::LoadedMetaData && m_networkState < LOADED_METADATA) {
411
m_player->seek(effectiveStart());
412
m_networkState = LOADED_METADATA;
414
dispatchEventForType(eventNames().durationchangeEvent, false, true);
415
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
418
dispatchEventForType(eventNames().loadedmetadataEvent, false, true);
419
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
423
if (state >= MediaPlayer::LoadedFirstFrame && m_networkState < LOADED_FIRST_FRAME) {
424
m_networkState = LOADED_FIRST_FRAME;
426
setReadyState(CAN_SHOW_CURRENT_FRAME);
429
static_cast<HTMLVideoElement*>(this)->updatePosterImage();
431
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
434
m_loadedFirstFrame = true;
436
ASSERT(!renderer()->isImage());
437
static_cast<RenderVideo*>(renderer())->videoSizeChanged();
440
dispatchEventForType(eventNames().loadedfirstframeEvent, false, true);
441
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
444
dispatchEventForType(eventNames().canshowcurrentframeEvent, false, true);
445
if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
450
if (state == MediaPlayer::Loaded && m_networkState < LOADED) {
452
m_networkState = LOADED;
453
m_progressEventTimer.stop();
455
initAndDispatchProgressEvent(eventNames().loadEvent);
688
beginProcessingMediaPlayerCallback();
689
setNetworkState(m_player->networkState());
690
endProcessingMediaPlayerCallback();
693
void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
695
if (state == MediaPlayer::Empty) {
696
// just update the cached state and leave, we can't do anything
697
m_networkState = NETWORK_EMPTY;
701
if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
702
stopPeriodicTimers();
704
// If we failed while trying to load a <source> element, the movie was never parsed, and there are more
705
// <source> children, schedule the next one
706
if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
707
m_currentSourceNode->scheduleErrorEvent();
708
if (havePotentialSourceChild())
709
scheduleNextSourceChild();
713
if (state == MediaPlayer::NetworkError)
714
mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
715
else if (state == MediaPlayer::DecodeError)
716
mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
717
else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr)
721
static_cast<HTMLVideoElement*>(this)->updatePosterImage();
726
if (state == MediaPlayer::Idle) {
727
if (m_networkState > NETWORK_IDLE) {
728
stopPeriodicTimers();
729
scheduleProgressEvent(eventNames().suspendEvent);
731
m_networkState = NETWORK_IDLE;
734
if (state == MediaPlayer::Loading) {
735
if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
736
startProgressEventTimer();
737
m_networkState = NETWORK_LOADING;
740
if (state == MediaPlayer::Loaded) {
741
NetworkState oldState = m_networkState;
743
m_networkState = NETWORK_LOADED;
744
if (oldState < NETWORK_LOADED || oldState == NETWORK_NO_SOURCE) {
745
m_progressEventTimer.stop();
747
// Schedule one last progress event so we guarantee that at least one is fired
748
// for files that load very quickly.
749
scheduleProgressEvent(eventNames().progressEvent);
751
// Check to see if readyState changes need to be dealt with before sending the
752
// 'load' event so we report 'canplaythrough' first. This is necessary because a
753
// media engine reports readyState and networkState changes separately
754
MediaPlayer::ReadyState currentState = m_player->readyState();
755
if (static_cast<ReadyState>(currentState) != m_readyState)
756
setReadyState(currentState);
758
scheduleProgressEvent(eventNames().loadEvent);
759
scheduleProgressEvent(eventNames().loadendEvent);
459
764
void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
461
MediaPlayer::ReadyState state = m_player->readyState();
462
setReadyState((ReadyState)state);
766
beginProcessingMediaPlayerCallback();
768
setReadyState(m_player->readyState());
770
endProcessingMediaPlayerCallback();
465
void HTMLMediaElement::setReadyState(ReadyState state)
773
void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
467
// 3.14.9.6. The ready states
468
if (m_readyState == state)
471
bool wasActivelyPlaying = activelyPlaying();
472
m_readyState = state;
474
if (state >= CAN_PLAY)
477
if (networkState() == EMPTY)
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);
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);
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);
775
// Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
776
bool wasPotentiallyPlaying = potentiallyPlaying();
778
ReadyState oldState = m_readyState;
779
m_readyState = static_cast<ReadyState>(state);
781
if (m_readyState == oldState)
784
if (m_networkState == NETWORK_EMPTY)
789
if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
790
scheduleEvent(eventNames().waitingEvent);
793
if (m_readyState < HAVE_CURRENT_DATA) {
794
if (oldState >= HAVE_CURRENT_DATA)
795
scheduleEvent(eventNames().seekingEvent);
797
// 4.8.10.10 step 12 & 13.
802
if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
804
scheduleTimeupdateEvent(false);
805
scheduleEvent(eventNames().waitingEvent);
809
if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
810
scheduleEvent(eventNames().durationchangeEvent);
811
scheduleEvent(eventNames().loadedmetadataEvent);
813
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
814
if (renderer() && renderer()->isVideo()) {
815
toRenderVideo(renderer())->videoSizeChanged();
818
m_delayingTheLoadEvent = false;
822
// 4.8.10.7 says loadeddata is sent only when the new state *is* HAVE_CURRENT_DATA: "If the
823
// previous ready state was HAVE_METADATA and the new ready state is HAVE_CURRENT_DATA",
824
// but the event table at the end of the spec says it is sent when: "readyState newly
825
// increased to HAVE_CURRENT_DATA or greater for the first time"
826
// We go with the later because it seems useful to count on getting this event
827
if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
828
m_haveFiredLoadedData = true;
829
scheduleEvent(eventNames().loadeddataEvent);
832
bool isPotentiallyPlaying = potentiallyPlaying();
833
if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) {
834
scheduleEvent(eventNames().canplayEvent);
835
if (isPotentiallyPlaying)
836
scheduleEvent(eventNames().playingEvent);
839
static_cast<HTMLVideoElement*>(this)->updatePosterImage();
842
if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA) {
843
if (oldState <= HAVE_CURRENT_DATA)
844
scheduleEvent(eventNames().canplayEvent);
846
scheduleEvent(eventNames().canplaythroughEvent);
848
if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
849
scheduleEvent(eventNames().playingEvent);
497
851
if (m_autoplaying && m_paused && autoplay()) {
498
852
m_paused = false;
499
dispatchEventForType(eventNames().playEvent, false, true);
853
scheduleEvent(eventNames().playEvent);
854
scheduleEvent(eventNames().playingEvent);
858
static_cast<HTMLVideoElement*>(this)->updatePosterImage();
502
861
updatePlayState();
505
864
void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
507
866
ASSERT(m_player);
867
if (m_networkState == NETWORK_EMPTY || m_networkState >= NETWORK_LOADED)
508
870
unsigned progress = m_player->bytesLoaded();
509
double time = WebCore::currentTime();
871
double time = WTF::currentTime();
510
872
double timedelta = time - m_previousProgressTime;
512
m_bufferingRate = (float)(0.8 * m_bufferingRate + 0.2 * ((float)(progress - m_previousProgress)) / timedelta);
514
874
if (progress == m_previousProgress) {
515
875
if (timedelta > 3.0 && !m_sentStalledEvent) {
517
initAndDispatchProgressEvent(eventNames().stalledEvent);
876
scheduleProgressEvent(eventNames().stalledEvent);
518
877
m_sentStalledEvent = true;
521
initAndDispatchProgressEvent(eventNames().progressEvent);
880
scheduleProgressEvent(eventNames().progressEvent);
522
881
m_previousProgress = progress;
523
882
m_previousProgressTime = time;
524
883
m_sentStalledEvent = false;
887
void HTMLMediaElement::rewind(float timeDelta)
890
setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
893
void HTMLMediaElement::returnToRealtime()
896
setCurrentTime(maxTimeSeekable(), e);
899
void HTMLMediaElement::addPlayedRange(float start, float end)
901
if (!m_playedTimeRanges)
902
m_playedTimeRanges = TimeRanges::create();
903
m_playedTimeRanges->add(start, end);
906
bool HTMLMediaElement::supportsSave() const
908
return m_player ? m_player->supportsSave() : false;
528
911
void HTMLMediaElement::seek(float time, ExceptionCode& ec)
913
// 4.8.10.10. Seeking
532
if (networkState() < LOADED_METADATA) {
915
if (m_readyState == HAVE_NOTHING || !m_player) {
533
916
ec = INVALID_STATE_ERR;
539
if (currentLoop() == 0)
540
minTime = effectiveStart();
542
minTime = effectiveLoopStart();
921
time = min(time, duration());
545
float maxTime = currentLoop() == playCount() - 1 ? effectiveEnd() : effectiveLoopEnd();
924
time = max(time, 0.0f);
548
time = min(time, maxTime);
551
time = max(time, minTime);
554
927
RefPtr<TimeRanges> seekableRanges = seekable();
555
928
if (!seekableRanges->contain(time)) {
556
929
ec = INDEX_SIZE_ERR;
561
m_currentTimeDuringSeek = time;
933
// avoid generating events when the time won't actually change
934
float now = currentTime();
940
if (m_lastSeekTime < now)
941
addPlayedRange(m_lastSeekTime, now);
943
m_lastSeekTime = time;
945
// 6 - set the seeking flag, it will be cleared when the engine tells is the time has actually changed
564
946
m_seeking = true;
567
dispatchEventForType(eventNames().timeupdateEvent, false, true);
949
scheduleTimeupdateEvent(false);
951
// 8 - this is covered, if necessary, when the engine signals a readystate change
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.
573
m_player->setEndTime(maxTime);
574
m_player->seek(time);
954
m_player->seek(time);
955
m_sentEndEvent = false;
958
void HTMLMediaElement::finishSeek()
960
// 4.8.10.10 Seeking step 12
963
// 4.8.10.10 Seeking step 13
964
scheduleEvent(eventNames().seekedEvent);
578
967
HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
816
1203
if (m_muted != muted) {
817
1204
m_muted = muted;
819
dispatchEventAsync(eventNames().volumechangeEvent);
1206
scheduleEvent(eventNames().volumechangeEvent);
1210
void HTMLMediaElement::togglePlayState()
1212
// We can safely call the internal play/pause methods, which don't check restrictions, because
1213
// this method is only called from the built-in media controller
1220
void HTMLMediaElement::beginScrubbing()
1224
// Because a media element stays in non-paused state when it reaches end, playback resumes
1225
// when the slider is dragged from the end to another position unless we pause first. Do
1226
// a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
1229
// Not at the end but we still want to pause playback so the media engine doesn't try to
1230
// continue playing during scrubbing. Pause without generating an event as we will
1231
// unpause after scrubbing finishes.
1232
setPausedInternal(true);
1237
void HTMLMediaElement::endScrubbing()
1239
if (m_pausedInternal)
1240
setPausedInternal(false);
1243
// The spec says to fire periodic timeupdate events (those sent while playing) every
1244
// "15 to 250ms", we choose the slowest frequency
1245
static const double maxTimeupdateEventFrequency = 0.25;
1247
void HTMLMediaElement::startPlaybackProgressTimer()
1249
if (m_playbackProgressTimer.isActive())
1252
m_previousProgressTime = WTF::currentTime();
1253
m_previousProgress = 0;
1254
m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
1257
void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
1260
if (!m_playbackRate)
1263
scheduleTimeupdateEvent(true);
1265
// FIXME: deal with cue ranges here
1268
void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
1270
double now = WTF::currentTime();
1271
double timedelta = now - m_lastTimeUpdateEventWallTime;
1273
// throttle the periodic events
1274
if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
1277
// Some media engines make multiple "time changed" callbacks at the same time, but we only want one
1278
// event at a given time so filter here
1279
float movieTime = m_player ? m_player->currentTime() : 0;
1280
if (movieTime != m_lastTimeUpdateEventMovieTime) {
1281
scheduleEvent(eventNames().timeupdateEvent);
1282
m_lastTimeUpdateEventWallTime = now;
1283
m_lastTimeUpdateEventMovieTime = movieTime;
823
1287
bool HTMLMediaElement::canPlay() const
825
return paused() || ended() || networkState() < LOADED_METADATA;
828
String HTMLMediaElement::pickMedia()
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))
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()))
844
if (source->hasAttribute(typeAttr)) {
845
String type = source->type().stripWhiteSpace();
847
// "type" can have parameters after a semi-colon, strip them before checking with the type registry
848
int semi = type.find(';');
850
type = type.left(semi).stripWhiteSpace();
852
if (!MIMETypeRegistry::isSupportedMediaMIMEType(type))
855
mediaSrc = source->src().string();
1289
return paused() || ended() || m_readyState < HAVE_METADATA;
1292
float HTMLMediaElement::percentLoaded() const
1296
float duration = m_player->duration();
1298
if (!duration || isinf(duration))
1302
RefPtr<TimeRanges> timeRanges = m_player->buffered();
1303
for (unsigned i = 0; i < timeRanges->length(); ++i) {
1304
ExceptionCode ignoredException;
1305
float start = timeRanges->start(i, ignoredException);
1306
float end = timeRanges->end(i, ignoredException);
1307
buffered += end - start;
1309
return buffered / duration;
1312
bool HTMLMediaElement::havePotentialSourceChild()
1314
// Stash the current <source> node so we can restore it after checking
1315
// to see there is another potential
1316
HTMLSourceElement* currentSourceNode = m_currentSourceNode;
1317
KURL nextURL = selectNextSourceChild(0, DoNothing);
1318
m_currentSourceNode = currentSourceNode;
1320
return nextURL.isValid();
1323
KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
1327
bool lookingForPreviousNode = m_currentSourceNode;
1328
bool canUse = false;
1330
for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
1331
if (!node->hasTagName(sourceTag))
1334
if (lookingForPreviousNode) {
1335
if (m_currentSourceNode == static_cast<HTMLSourceElement*>(node))
1336
lookingForPreviousNode = false;
1340
HTMLSourceElement* source = static_cast<HTMLSourceElement*>(node);
1341
if (!source->hasAttribute(srcAttr))
1344
if (source->hasAttribute(mediaAttr)) {
1345
MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
1346
RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
1347
if (!screenEval.eval(media.get()))
1351
if (source->hasAttribute(typeAttr)) {
1352
if (!MediaPlayer::supportsType(ContentType(source->type())))
1356
// Is it safe to load this url?
1357
mediaURL = source->src();
1358
if (!mediaURL.isValid() || !isSafeToLoadURL(mediaURL, actionIfInvalid))
1361
// Making it this far means the <source> looks reasonable
1364
*contentType = ContentType(source->type());
1367
if (!canUse && actionIfInvalid == Complain)
1368
source->scheduleErrorEvent();
1369
m_currentSourceNode = static_cast<HTMLSourceElement*>(node);
1373
m_currentSourceNode = 0;
1374
return canUse ? mediaURL : KURL();
1377
void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
1379
beginProcessingMediaPlayerCallback();
1381
// 4.8.10.10 step 12 & 13. Needed if no ReadyState change is associated with the seek.
1382
if (m_readyState >= HAVE_CURRENT_DATA && m_seeking) {
1386
float now = currentTime();
1387
float dur = duration();
1388
if (!isnan(dur) && dur && now >= dur) {
1390
ExceptionCode ignoredException;
1391
m_sentEndEvent = false;
1392
seek(0, ignoredException);
1394
if (!m_sentEndEvent) {
1395
m_sentEndEvent = true;
1396
scheduleTimeupdateEvent(false);
1397
scheduleEvent(eventNames().endedEvent);
860
if (!mediaSrc.isEmpty())
861
mediaSrc = document()->completeURL(mediaSrc).string();
865
void HTMLMediaElement::checkIfSeekNeeded()
867
// 3.14.9.5. Offsets into the media resource
869
if (playCount() <= m_currentLoop)
870
m_currentLoop = playCount() - 1;
873
if (networkState() <= LOADING)
878
float time = currentTime();
879
if (!m_currentLoop && time < effectiveStart())
880
seek(effectiveStart(), ec);
883
if (m_currentLoop && time < effectiveLoopStart())
884
seek(effectiveLoopStart(), ec);
887
if (m_currentLoop < playCount() - 1 && time > effectiveLoopEnd()) {
888
seek(effectiveLoopStart(), ec);
893
if (m_currentLoop == playCount() - 1 && time > effectiveEnd())
894
seek(effectiveEnd(), ec);
899
void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
901
if (readyState() >= CAN_PLAY)
904
if (m_currentLoop < playCount() - 1 && currentTime() >= effectiveLoopEnd()) {
906
seek(effectiveLoopStart(), ec);
908
dispatchEventForType(eventNames().timeupdateEvent, false, true);
911
if (m_currentLoop == playCount() - 1 && currentTime() >= effectiveEnd()) {
912
dispatchEventForType(eventNames().timeupdateEvent, false, true);
913
dispatchEventForType(eventNames().endedEvent, false, true);
1402
m_sentEndEvent = false;
1405
endProcessingMediaPlayerCallback();
1408
void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
1410
beginProcessingMediaPlayerCallback();
1412
endProcessingMediaPlayerCallback();
1415
void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
1417
beginProcessingMediaPlayerCallback();
1418
scheduleEvent(eventNames().durationchangeEvent);
1419
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1421
renderer()->updateFromElement();
1422
if (renderer()->isVideo())
1423
toRenderVideo(renderer())->videoSizeChanged();
1426
endProcessingMediaPlayerCallback();
1429
void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
1431
beginProcessingMediaPlayerCallback();
1432
// Stash the rate in case the one we tried to set isn't what the engine is
1433
// using (eg. it can't handle the rate we set)
1434
m_playbackRate = m_player->rate();
1435
endProcessingMediaPlayerCallback();
1438
void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
1440
// The MediaPlayer came across content it cannot completely handle.
1441
// This is normally acceptable except when we are in a standalone
1442
// MediaDocument. If so, tell the document what has happened.
1443
if (ownerDocument()->isMediaDocument()) {
1444
MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
1445
mediaDocument->mediaElementSawUnsupportedTracks();
1449
// MediaPlayerPresentation methods
919
1450
void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
1452
beginProcessingMediaPlayerCallback();
922
1454
renderer()->repaint();
1455
endProcessingMediaPlayerCallback();
1458
void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
1460
beginProcessingMediaPlayerCallback();
1461
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1462
if (renderer() && renderer()->isVideo())
1463
toRenderVideo(renderer())->videoSizeChanged();
1465
endProcessingMediaPlayerCallback();
1468
#if USE(ACCELERATED_COMPOSITING)
1469
bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
1471
if (renderer() && renderer()->isVideo()) {
1472
ASSERT(renderer()->view());
1473
return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
1478
GraphicsLayer* HTMLMediaElement::mediaPlayerGraphicsLayer(MediaPlayer*)
1480
if (renderer() && renderer()->isVideo())
1481
return toRenderVideo(renderer())->videoGraphicsLayer();
925
1486
PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
927
// FIXME real ranges support
928
if (!m_player || !m_player->maxTimeBuffered())
929
1489
return TimeRanges::create();
930
return TimeRanges::create(0, m_player->maxTimeBuffered());
1490
return m_player->buffered();
933
PassRefPtr<TimeRanges> HTMLMediaElement::played() const
1493
PassRefPtr<TimeRanges> HTMLMediaElement::played()
935
// FIXME track played
936
return TimeRanges::create();
1496
float time = currentTime();
1497
if (time > m_lastSeekTime)
1498
addPlayedRange(m_lastSeekTime, time);
1501
if (!m_playedTimeRanges)
1502
m_playedTimeRanges = TimeRanges::create();
1504
return m_playedTimeRanges->copy();
939
1507
PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
941
1509
// FIXME real ranges support
942
if (!m_player || !m_player->maxTimeSeekable())
1510
if (!maxTimeSeekable())
943
1511
return TimeRanges::create();
944
return TimeRanges::create(0, m_player->maxTimeSeekable());
947
float HTMLMediaElement::effectiveStart() const
951
return min(start(), m_player->duration());
954
float HTMLMediaElement::effectiveEnd() const
958
return min(max(end(), max(start(), loopStart())), m_player->duration());
961
float HTMLMediaElement::effectiveLoopStart() const
965
return min(loopStart(), m_player->duration());
968
float HTMLMediaElement::effectiveLoopEnd() const
972
return min(max(start(), max(loopStart(), loopEnd())), m_player->duration());
975
bool HTMLMediaElement::activelyPlaying() const
977
return !paused() && readyState() >= CAN_PLAY && !endedPlayback(); // && !stoppedDueToErrors() && !pausedForUserInteraction();
1512
return TimeRanges::create(minTimeSeekable(), maxTimeSeekable());
1515
bool HTMLMediaElement::potentiallyPlaying() const
1517
return !paused() && m_readyState >= HAVE_FUTURE_DATA && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
980
1520
bool HTMLMediaElement::endedPlayback() const
982
return networkState() >= LOADED_METADATA && currentTime() >= effectiveEnd() && currentLoop() == playCount() - 1;
1522
if (!m_player || m_readyState < HAVE_METADATA)
1525
float dur = duration();
1526
return !isnan(dur) && currentTime() >= dur && !loop();
1529
bool HTMLMediaElement::stoppedDueToErrors() const
1531
if (m_readyState >= HAVE_METADATA && m_error) {
1532
RefPtr<TimeRanges> seekableRanges = seekable();
1533
if (!seekableRanges->contain(currentTime()))
1540
bool HTMLMediaElement::pausedForUserInteraction() const
1542
// return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
1546
float HTMLMediaElement::minTimeSeekable() const
1551
float HTMLMediaElement::maxTimeSeekable() const
1553
return m_player ? m_player->maxTimeSeekable() : 0;
985
1556
void HTMLMediaElement::updateVolume()