diff options
Diffstat (limited to 'WebCore/html/HTMLMediaElement.cpp')
-rw-r--r-- | WebCore/html/HTMLMediaElement.cpp | 87 |
1 files changed, 63 insertions, 24 deletions
diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp index 751735d..bc7960c 100644 --- a/WebCore/html/HTMLMediaElement.cpp +++ b/WebCore/html/HTMLMediaElement.cpp @@ -37,7 +37,6 @@ #include "ClientRect.h" #include "ClientRectList.h" #include "ContentType.h" -#include "DocLoader.h" #include "Event.h" #include "EventNames.h" #include "ExceptionCode.h" @@ -112,7 +111,8 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc) , m_processingMediaPlayerCallback(0) , m_playing(false) , m_isWaitingUntilMediaCanStart(false) - , m_delayingTheLoadEvent(false) + , m_shouldDelayLoadEvent(false) + , m_isWaitingToDecrementLoadEventDelayCount(false) , m_haveFiredLoadedData(false) , m_inActiveDocument(true) , m_autoplaying(true) @@ -140,6 +140,7 @@ HTMLMediaElement::~HTMLMediaElement() { if (m_isWaitingUntilMediaCanStart) document()->removeMediaCanStartListener(this); + setShouldDelayLoadEvent(false); document()->unregisterForDocumentActivationCallbacks(this); document()->unregisterForMediaVolumeCallbacks(this); } @@ -148,6 +149,7 @@ void HTMLMediaElement::willMoveToNewOwnerDocument() { if (m_isWaitingUntilMediaCanStart) document()->removeMediaCanStartListener(this); + setShouldDelayLoadEvent(false); document()->unregisterForDocumentActivationCallbacks(this); document()->unregisterForMediaVolumeCallbacks(this); HTMLElement::willMoveToNewOwnerDocument(); @@ -157,6 +159,8 @@ void HTMLMediaElement::didMoveToNewOwnerDocument() { if (m_isWaitingUntilMediaCanStart) document()->addMediaCanStartListener(this); + if (m_readyState < HAVE_CURRENT_DATA) + setShouldDelayLoadEvent(true); document()->registerForDocumentActivationCallbacks(this); document()->registerForMediaVolumeCallbacks(this); HTMLElement::didMoveToNewOwnerDocument(); @@ -368,6 +372,15 @@ void HTMLMediaElement::scheduleEvent(const AtomicString& eventName) void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*) { + // If we are waiting to release our delay on the load event, do that first and post + // the pending events on the next go around. + if (m_isWaitingToDecrementLoadEventDelayCount) { + setShouldDelayLoadEvent(false); + if (!m_asyncEventTimer.isActive()) + m_asyncEventTimer.startOneShot(0); + return; + } + Vector<RefPtr<Event> > pendingEvents; ExceptionCode ec = 0; @@ -541,6 +554,11 @@ void HTMLMediaElement::prepareForLoad() m_playedTimeRanges = TimeRanges::create(); m_lastSeekTime = 0; m_closedCaptionsVisible = false; + + // The spec doesn't say to block the load event until we actually run the asynchronous section + // algorithm, but do it now because we won't start that until after the timer fires and the + // event may have already fired by then. + setShouldDelayLoadEvent(true); } void HTMLMediaElement::loadInternal() @@ -574,18 +592,19 @@ void HTMLMediaElement::selectMediaResource() if (!node) { m_loadState = WaitingForSource; + setShouldDelayLoadEvent(false); // ... set the networkState to NETWORK_EMPTY, and abort these steps m_networkState = NETWORK_EMPTY; - ASSERT(!m_delayingTheLoadEvent); return; } mode = children; } - // 4 - m_delayingTheLoadEvent = true; + // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event), + // and set its networkState to NETWORK_LOADING. + setShouldDelayLoadEvent(true); m_networkState = NETWORK_LOADING; // 5 @@ -715,7 +734,7 @@ void HTMLMediaElement::waitForSourceChange() m_networkState = NETWORK_NO_SOURCE; // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event. - m_delayingTheLoadEvent = false; + setShouldDelayLoadEvent(false); } void HTMLMediaElement::noneSupported() @@ -738,7 +757,7 @@ void HTMLMediaElement::noneSupported() scheduleEvent(eventNames().errorEvent); // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event. - m_delayingTheLoadEvent = false; + setShouldDelayLoadEvent(false); // 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource. @@ -758,8 +777,7 @@ void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err) // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE. m_error = err; - // 3 - Queue a task to fire a progress event called error at the media element, in - // the context of the fetching process started by this instance of this algorithm. + // 3 - Queue a task to fire a simple event named error at the media element. scheduleEvent(eventNames().errorEvent); // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a @@ -768,7 +786,7 @@ void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err) scheduleEvent(eventNames().emptiedEvent); // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event. - m_delayingTheLoadEvent = false; + setShouldDelayLoadEvent(false); // 6 - Abort the overall resource selection algorithm. m_currentSourceNode = 0; @@ -915,21 +933,16 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state) scheduleEvent(eventNames().loadedmetadataEvent); if (renderer()) renderer()->updateFromElement(); - m_delayingTheLoadEvent = false; m_player->seek(0); } bool shouldUpdateDisplayState = false; - // 4.8.10.7 says loadeddata is sent only when the new state *is* HAVE_CURRENT_DATA: "If the - // previous ready state was HAVE_METADATA and the new ready state is HAVE_CURRENT_DATA", - // but the event table at the end of the spec says it is sent when: "readyState newly - // increased to HAVE_CURRENT_DATA or greater for the first time" - // We go with the later because it seems useful to count on getting this event if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) { m_haveFiredLoadedData = true; shouldUpdateDisplayState = true; scheduleEvent(eventNames().loadeddataEvent); + setShouldDelayLoadEvent(false); } bool isPotentiallyPlaying = potentiallyPlaying(); @@ -1818,13 +1831,12 @@ void HTMLMediaElement::userCancelledLoad() // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED. m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED); - // 3 - Queue a task to fire a progress event called abort at the media element, in the context - // of the fetching process started by this instance of this algorithm. + // 3 - Queue a task to fire a simple event named error at the media element. scheduleEvent(eventNames().abortEvent); - // 5 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the - // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a - // simple event called emptied at the element. Otherwise, set set the element's networkState + // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the + // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a + // simple event named emptied at the element. Otherwise, set the element's networkState // attribute to the NETWORK_IDLE value. if (m_readyState == HAVE_NOTHING) { m_networkState = NETWORK_EMPTY; @@ -1833,10 +1845,10 @@ void HTMLMediaElement::userCancelledLoad() else m_networkState = NETWORK_IDLE; - // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event. - m_delayingTheLoadEvent = false; + // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event. + setShouldDelayLoadEvent(false); - // 7 - Abort the overall resource selection algorithm. + // 6 - Abort the overall resource selection algorithm. m_currentSourceNode = 0; // Reset m_readyState since m_player is gone. @@ -2087,6 +2099,33 @@ bool HTMLMediaElement::isURLAttribute(Attribute* attribute) const return attribute->name() == srcAttr; } +void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay) +{ + if (m_shouldDelayLoadEvent == shouldDelay) + return; + + // Don't decrement the load event delay if we are in the middle of a callback from + // the media engine. The load event is sent synchronously and may trigger a script that + // causes the document to be come inactive and that will clear the media engine, causing + // the return to be a rough one. + if (!shouldDelay && processingMediaPlayerCallback()) { + m_isWaitingToDecrementLoadEventDelayCount = true; + + // Instead of creating yet-another-timer, reuse the async event timer which is always + // used as a one-shot. + if (!m_asyncEventTimer.isActive()) + m_asyncEventTimer.startOneShot(0); + return; + } + + m_shouldDelayLoadEvent = shouldDelay; + m_isWaitingToDecrementLoadEventDelayCount = false; + if (shouldDelay) + document()->incrementLoadEventDelayCount(); + else + document()->decrementLoadEventDelayCount(); +} + } #endif |