summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLMediaElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/HTMLMediaElement.cpp')
-rw-r--r--WebCore/html/HTMLMediaElement.cpp87
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