| Index: Source/WebCore/html/HTMLMediaElement.cpp
|
| ===================================================================
|
| --- Source/WebCore/html/HTMLMediaElement.cpp (revision 112578)
|
| +++ Source/WebCore/html/HTMLMediaElement.cpp (working copy)
|
| @@ -190,8 +190,6 @@
|
| , m_lastTimeUpdateEventWallTime(0)
|
| , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max())
|
| , m_loadState(WaitingForSource)
|
| - , m_currentSourceNode(0)
|
| - , m_nextChildNodeToConsider(0)
|
| #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
|
| , m_proxyWidget(0)
|
| #endif
|
| @@ -548,6 +546,8 @@
|
|
|
| void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
|
| {
|
| + RefPtr<HTMLMediaElement> protect(this); // loadNextSourceChild may fire 'beforeload', which can make arbitrary DOM mutations.
|
| +
|
| if (m_pendingLoadFlags & MediaResource) {
|
| if (m_loadState == LoadingFromSourceElement)
|
| loadNextSourceChild();
|
| @@ -604,6 +604,8 @@
|
|
|
| void HTMLMediaElement::load(ExceptionCode& ec)
|
| {
|
| + RefPtr<HTMLMediaElement> protect(this); // loadInternal may result in a 'beforeload' event, which can make arbitrary DOM mutations.
|
| +
|
| LOG(Media, "HTMLMediaElement::load()");
|
|
|
| if (userGestureRequiredForLoad() && !ScriptController::processingUserGesture())
|
| @@ -757,7 +759,7 @@
|
| // source element child in tree order.
|
| if (node) {
|
| mode = children;
|
| - m_nextChildNodeToConsider = 0;
|
| + m_nextChildNodeToConsider = node;
|
| m_currentSourceNode = 0;
|
| } else {
|
| // Otherwise the media element has neither a src attribute nor a source element
|
| @@ -2451,8 +2453,8 @@
|
| {
|
| // Stash the current <source> node and next nodes so we can restore them after checking
|
| // to see there is another potential.
|
| - HTMLSourceElement* currentSourceNode = m_currentSourceNode;
|
| - Node* nextNode = m_nextChildNodeToConsider;
|
| + RefPtr<HTMLSourceElement> currentSourceNode = m_currentSourceNode;
|
| + RefPtr<Node> nextNode = m_nextChildNodeToConsider;
|
|
|
| KURL nextURL = selectNextSourceChild(0, DoNothing);
|
|
|
| @@ -2471,7 +2473,7 @@
|
| LOG(Media, "HTMLMediaElement::selectNextSourceChild");
|
| #endif
|
|
|
| - if (m_nextChildNodeToConsider == sourceChildEndOfListValue()) {
|
| + if (!m_nextChildNodeToConsider) {
|
| #if !LOG_DISABLED
|
| if (shouldLog)
|
| LOG(Media, "HTMLMediaElement::selectNextSourceChild -> 0x0000, \"\"");
|
| @@ -2482,16 +2484,24 @@
|
| KURL mediaURL;
|
| Node* node;
|
| HTMLSourceElement* source = 0;
|
| + String type;
|
| bool lookingForStartNode = m_nextChildNodeToConsider;
|
| - bool canUse = false;
|
| + bool canUseSourceElement = false;
|
| + bool okToLoadSourceURL;
|
|
|
| - for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
|
| + NodeVector potentialSourceNodes;
|
| + getChildNodes(this, potentialSourceNodes);
|
| +
|
| + for (unsigned i = 0; !canUseSourceElement && i < potentialSourceNodes.size(); ++i) {
|
| + node = potentialSourceNodes[i].get();
|
| if (lookingForStartNode && m_nextChildNodeToConsider != node)
|
| continue;
|
| lookingForStartNode = false;
|
| -
|
| +
|
| if (!node->hasTagName(sourceTag))
|
| continue;
|
| + if (node->parentNode() != this)
|
| + continue;
|
|
|
| source = static_cast<HTMLSourceElement*>(node);
|
|
|
| @@ -2525,34 +2535,41 @@
|
| }
|
|
|
| // Is it safe to load this url?
|
| - if (!isSafeToLoadURL(mediaURL, actionIfInvalid) || !dispatchBeforeLoadEvent(mediaURL.string()))
|
| + okToLoadSourceURL = isSafeToLoadURL(mediaURL, actionIfInvalid) && dispatchBeforeLoadEvent(mediaURL.string());
|
| +
|
| + // A 'beforeload' event handler can mutate the DOM, so check to see if the source element is still a child node.
|
| + if (node->parentNode() != this) {
|
| + LOG(Media, "HTMLMediaElement::selectNextSourceChild : 'beforeload' removed current element");
|
| + source = 0;
|
| goto check_again;
|
| + }
|
|
|
| + if (!okToLoadSourceURL)
|
| + goto check_again;
|
| +
|
| // Making it this far means the <source> looks reasonable.
|
| - canUse = true;
|
| + canUseSourceElement = true;
|
|
|
| check_again:
|
| - if (!canUse && actionIfInvalid == Complain)
|
| + if (!canUseSourceElement && actionIfInvalid == Complain && source)
|
| source->scheduleErrorEvent();
|
| }
|
|
|
| - if (canUse) {
|
| + if (canUseSourceElement) {
|
| if (contentType)
|
| *contentType = ContentType(source->type());
|
| m_currentSourceNode = source;
|
| m_nextChildNodeToConsider = source->nextSibling();
|
| - if (!m_nextChildNodeToConsider)
|
| - m_nextChildNodeToConsider = sourceChildEndOfListValue();
|
| } else {
|
| m_currentSourceNode = 0;
|
| - m_nextChildNodeToConsider = sourceChildEndOfListValue();
|
| + m_nextChildNodeToConsider = 0;
|
| }
|
|
|
| #if !LOG_DISABLED
|
| if (shouldLog)
|
| - LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode, canUse ? urlForLogging(mediaURL).utf8().data() : "");
|
| + LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode.get(), canUseSourceElement ? urlForLogging(mediaURL).utf8().data() : "");
|
| #endif
|
| - return canUse ? mediaURL : KURL();
|
| + return canUseSourceElement ? mediaURL : KURL();
|
| }
|
|
|
| void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
|
| @@ -2584,20 +2601,20 @@
|
| return;
|
| }
|
|
|
| - if (m_nextChildNodeToConsider != sourceChildEndOfListValue())
|
| + if (m_nextChildNodeToConsider)
|
| return;
|
|
|
| // 4.8.9.5, resource selection algorithm, source elements section:
|
| - // 20 - Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
|
| - // 21 - Asynchronously await a stable state...
|
| - // 22 - Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case
|
| + // 21. Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
|
| + // 22. Asynchronously await a stable state...
|
| + // 23. Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case
|
| // it hasn't been fired yet).
|
| setShouldDelayLoadEvent(true);
|
|
|
| - // 23 - Set the networkState back to NETWORK_LOADING.
|
| + // 24. Set the networkState back to NETWORK_LOADING.
|
| m_networkState = NETWORK_LOADING;
|
|
|
| - // 24 - Jump back to the find next candidate step above.
|
| + // 25. Jump back to the find next candidate step above.
|
| m_nextChildNodeToConsider = source;
|
| scheduleNextSourceChild();
|
| }
|
| @@ -2619,8 +2636,8 @@
|
| if (source == m_nextChildNodeToConsider) {
|
| m_nextChildNodeToConsider = m_nextChildNodeToConsider->nextSibling();
|
| if (!m_nextChildNodeToConsider)
|
| - m_nextChildNodeToConsider = sourceChildEndOfListValue();
|
| - LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider);
|
| + m_nextChildNodeToConsider = 0;
|
| + LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider.get());
|
| } else if (source == m_currentSourceNode) {
|
| // Clear the current source node pointer, but don't change the movie as the spec says:
|
| // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already
|
| @@ -3212,6 +3229,8 @@
|
|
|
| void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values)
|
| {
|
| + RefPtr<HTMLMediaElement> protect(this); // selectNextSourceChild may fire 'beforeload', which can make arbitrary DOM mutations.
|
| +
|
| Frame* frame = document()->frame();
|
|
|
| if (isVideo()) {
|
|
|