2009-05-08 Eric Carlson <eric.carlson@apple.com>

        Reviewed by Darin Adler.
        
        https://bugs.webkit.org/show_bug.cgi?id=25627
        Bug 25627: HTMLMediaElement: some errors should fire on <source> elements

        Update for HTML5 spec change to fire 'error' events on <source> element
        when there is a failure while processing/loading a <source>.

        Test: media/video-source-error.html

        * html/HTMLMediaElement.cpp:
        (WebCore::HTMLMediaElement::enqueueEvent): Remove white-space.
        (WebCore::HTMLMediaElement::loadInternal): Call cancelPendingEventsAndCallbacks instead
        of just calling m_pendingEvents.clear() as we now also need to cancel pending errors on
        all <source> element. 
        (WebCore::HTMLMediaElement::selectMediaResource): Call isSafeToLoadURL() here instead of in
        loadResource() as we need to report errors differently depending on the type of failure. Use
        KURL instead of String.
        (WebCore::HTMLMediaElement::loadNextSourceChild): nextSourceChild -> selectNextSourceChild.
        Fail silently when there are no more <source> canditates because that is what spec mandates.
        Keep url as KURL instead of converting to String.
        (WebCore::HTMLMediaElement::loadResource): ASSERT that the URL is safe to load as we now 
        assume the safety check now done before this function. Takes KURL instead of String.
        (WebCore::HTMLMediaElement::isSafeToLoadURL): New, checks to see if a url is safe to load, logs
        failure if not.
        (WebCore::HTMLMediaElement::noneSupported): MEDIA_ERR_NONE_SUPPORTED -> MEDIA_ERR_SRC_NOT_SUPPORTED
        (WebCore::HTMLMediaElement::cancelPendingEventsAndCallbacks): New, clear all events pending on
        the media and all source elements.
        (WebCore::HTMLMediaElement::setNetworkState): Fire an error on the source element when the 
        the failure happened while processing one. Only call nonSupported() when the failure happened
        while processing media element 'src' attribute.
        (WebCore::HTMLMediaElement::havePotentialSourceChild): nextSourceChild -> selectNextSourceChild.
        Deal with selectNextSourceChild returning a KURL instead of a String.
        (WebCore::HTMLMediaElement::selectNextSourceChild): Renamed from nextSourceChild, add optional
        param to control whether or not errors are fired on a source element when it will not be used.
        Check safety of url here instead of waiting until loadResource(). Return a KURL instead of a
        String.
        (WebCore::HTMLMediaElement::initialURL): nextSourceChild -> selectNextSourceChild. Keep url as
        a KURL instead of a String.
        * html/HTMLMediaElement.h:
        (WebCore::HTMLMediaElement::):

        * html/HTMLSourceElement.cpp:
        (WebCore::HTMLSourceElement::HTMLSourceElement): Initialize timer related variables.
        (WebCore::HTMLSourceElement::scheduleErrorEvent): New, start one-shot timer to fire an error
        event ASAP.
        (WebCore::HTMLSourceElement::cancelPendingErrorEvent): New, cancel pending error event.
        (WebCore::HTMLSourceElement::errorEventTimerFired): New, fire error event if it has not been
        cancelled.
        * html/HTMLSourceElement.h:

        * html/MediaError.h: 
        (WebCore::MediaError::): MEDIA_ERR_NONE_SUPPORTED -> MEDIA_ERR_SRC_NOT_SUPPORTED
        * html/MediaError.idl: Ditto

2009-05-08  Eric Carlson  <eric.carlson@apple.com>

        Reviewed by Darin Adler.

        https://bugs.webkit.org/show_bug.cgi?id=25627
        Bug 25627: HTMLMediaElement: some errors should fire on <source> elements

        Update tests for MEDIA_ERR_NONE_SUPPORTED change to MEDIA_ERR_SRC_NOT_SUPPORTED.
        Add video-source-error.html to test errors fired on <source> elements .

        * media/media-constants-expected.txt:
        * media/media-constants.html:
        * media/unsupported-rtsp.html:
        * media/video-error-does-not-exist.html:
        * media/video-source-error.html: Added.
        * media/video-src-change.html:
        * media/video-src-invalid-remove.html:
        * media/video-src-plus-source.html:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@43403 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent be247172
2009-05-08 Eric Carlson <eric.carlson@apple.com>
Reviewed by Darin Adler.
https://bugs.webkit.org/show_bug.cgi?id=25627
Bug 25627: HTMLMediaElement: some errors should fire on <source> elements
Update tests for MEDIA_ERR_NONE_SUPPORTED change to MEDIA_ERR_SRC_NOT_SUPPORTED.
Add video-source-error.html to test errors fired on <source> elements .
* media/media-constants-expected.txt:
* media/media-constants.html:
* media/unsupported-rtsp.html:
* media/video-error-does-not-exist.html:
* media/video-source-error.html: Added.
* media/video-src-change.html:
* media/video-src-invalid-remove.html:
* media/video-src-plus-source.html:
2009-05-06 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
Disable new test that is failing.
......@@ -15,6 +15,6 @@ EXPECTED (HTMLMediaElement.HAVE_ENOUGH_DATA == '4') OK
EXPECTED (MediaError.MEDIA_ERR_ABORTED == '1') OK
EXPECTED (MediaError.MEDIA_ERR_NETWORK == '2') OK
EXPECTED (MediaError.MEDIA_ERR_DECODE == '3') OK
EXPECTED (MediaError.MEDIA_ERR_NONE_SUPPORTED == '4') OK
EXPECTED (MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED == '4') OK
END OF TEST
......@@ -22,7 +22,7 @@
testExpected("MediaError.MEDIA_ERR_ABORTED", 1);
testExpected("MediaError.MEDIA_ERR_NETWORK", 2);
testExpected("MediaError.MEDIA_ERR_DECODE", 3);
testExpected("MediaError.MEDIA_ERR_NONE_SUPPORTED", 4);
testExpected("MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED", 4);
endTest();
......
......@@ -8,7 +8,7 @@
video.src = "rtsp://a2047.v1411b.c1411.g.vq.akamaistream.net/5/2047/1411/2_h264_650/1a1a1ae454c430950065de4cbb2f94c226950c7ae655b61a48a91475e243acda3dac194879adde0f/wwdc_2006_2_650.mov";
waitForEvent("error", function () {
testExpected("video.error", null, "!=");
testExpected("video.error.code", MediaError.MEDIA_ERR_NONE_SUPPORTED);
testExpected("video.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
testExpected("video.networkState", HTMLMediaElement.NETWORK_NO_SOURCE);
endTest();
});
......
......@@ -10,7 +10,7 @@
waitForEvent("error", function () {
testExpected("video.error", null, "!=");
testExpected("video.error.code", MediaError.MEDIA_ERR_NONE_SUPPORTED);
testExpected("video.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
testExpected("video.networkState", HTMLMediaElement.NETWORK_NO_SOURCE);
......
1. Test that errors fired while evaluating/loading <source> elements are fired at the <source> and not at the <video> element.
2. Verifiy that an 'error' event fired while processing/loading a <source> element does not set the media element's 'error' attribute.
EVENT(loadstart)
EVENT(error) from <source id='missing-src' src=''> OK
EXPECTED (video.error == 'null') OK
EVENT(error) from <source id='bogus-type' src='content/test.mp4'> OK
EXPECTED (video.error == 'null') OK
EVENT(error) from <source id='unsupported-media-query' src='content/test.mp4'> OK
EXPECTED (video.error == 'null') OK
EVENT(error) from <source id='missing-file' src='content/error2.mpeg'> OK
EXPECTED (video.error == 'null') OK
EVENT(error) from <source id='format-error' src='content/unsupported_track.mov'> OK
EXPECTED (video.error == 'null') OK
EVENT(durationchange)
EVENT(loadeddata)
EXPECTED (relativeURL(video.currentSrc) == 'content/test.mp4') OK
EXPECTED (video.error == 'null') OK
END OF TEST
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>&lt;video&gt; and &lt;source&gt; error test</title>
<script src=video-test.js></script>
<script>
var sources = [];
function loadeddata()
{
consoleWrite("");
testExpected("relativeURL(video.currentSrc)", "content/test.mp4");
testExpected("video.error", null);
consoleWrite("");
endTest();
}
function errorEvent(evt)
{
var ndx;
for (ndx = 0; ndx < sources.length; ndx++) {
if (sources[ndx] == evt.target)
break;
}
if (sources[ndx] == evt.target)
logResult(true, "EVENT(error) from &lt;source id='<em>" + evt.target.id + "</em>' src='<em>" + relativeURL(evt.target.src) + "</em>'&gt;");
else
logResult(false, "EVENT(error) from " + evt.target);
testExpected("video.error", null);
consoleWrite("");
}
function start()
{
findMediaElement();
sources = document.getElementsByTagName('source');
document.addEventListener("error", errorEvent, true);
waitForEvent("loadstart");
waitForEvent("ratechange");
waitForEvent("waiting");
waitForEvent("ratechange");
waitForEvent("durationchange");
waitForEvent("pause");
waitForEvent("play");
waitForEvent("playing");
waitForEvent('loadeddata', loadeddata);
}
</script>
</head>
<body onload="start()">
<video controls>
<source id=missing-src type="video/blahblah">
<source id=bogus-type src=content/test.mp4 type="video/blahblah">
<source id=unsupported-media-query src=content/test.mp4 media=print>
<source id=missing-file src=content/error2.mpeg type=video/mpeg>
<source id=format-error src="content/unsupported_track.mov">
<source id=supported-format src=content/test.mp4 type="video/mpeg; codecs=&quot;avc1.4D400C&quot;">
</video>
<p>1. Test that errors fired while evaluating/loading &lt;source&gt; elements are fired at the
&lt;source&gt; and not at the &lt;video&gt; element.
<br>2. Verifiy that an 'error' event fired while processing/loading a &lt;source&gt; element
does not set the media element's 'error' attribute.</p>
</body>
</html>
......@@ -15,7 +15,7 @@
{
testExpected("relativeURL(video.currentSrc)", "bogus");
testExpected("video.networkState", HTMLMediaElement.NETWORK_NO_SOURCE);
testExpected("video.error.code", MediaError.MEDIA_ERR_NONE_SUPPORTED);
testExpected("video.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
consoleWrite("");
run("video.setAttribute('src', 'content/test.mp4')");
consoleWrite("");
......
......@@ -34,7 +34,7 @@
function errorEvent()
{
testExpected("video.error.code", MediaError.MEDIA_ERR_NONE_SUPPORTED);
testExpected("video.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
setTimeout(function () { endTest(); } , 500) ;
run("video.removeAttribute('src')");
consoleWrite("");
......
......@@ -20,7 +20,7 @@
waitForEvent('error', function () {
testExpected("relativeURL(video.currentSrc)", "content/bogus.mpeg");
testExpected("media.error.code", MediaError.MEDIA_ERR_NONE_SUPPORTED);
testExpected("media.error.code", MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
setTimeout(endTest, 200) ;
consoleWrite("");
});
......
2009-05-08 Eric Carlson <eric.carlson@apple.com>
Reviewed by Darin Adler.
https://bugs.webkit.org/show_bug.cgi?id=25627
Bug 25627: HTMLMediaElement: some errors should fire on <source> elements
Update for HTML5 spec change to fire 'error' events on <source> element
when there is a failure while processing/loading a <source>.
Test: media/video-source-error.html
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::enqueueEvent): Remove white-space.
(WebCore::HTMLMediaElement::loadInternal): Call cancelPendingEventsAndCallbacks instead
of just calling m_pendingEvents.clear() as we now also need to cancel pending errors on
all <source> element.
(WebCore::HTMLMediaElement::selectMediaResource): Call isSafeToLoadURL() here instead of in
loadResource() as we need to report errors differently depending on the type of failure. Use
KURL instead of String.
(WebCore::HTMLMediaElement::loadNextSourceChild): nextSourceChild -> selectNextSourceChild.
Fail silently when there are no more <source> canditates because that is what spec mandates.
Keep url as KURL instead of converting to String.
(WebCore::HTMLMediaElement::loadResource): ASSERT that the URL is safe to load as we now
assume the safety check now done before this function. Takes KURL instead of String.
(WebCore::HTMLMediaElement::isSafeToLoadURL): New, checks to see if a url is safe to load, logs
failure if not.
(WebCore::HTMLMediaElement::noneSupported): MEDIA_ERR_NONE_SUPPORTED -> MEDIA_ERR_SRC_NOT_SUPPORTED
(WebCore::HTMLMediaElement::cancelPendingEventsAndCallbacks): New, clear all events pending on
the media and all source elements.
(WebCore::HTMLMediaElement::setNetworkState): Fire an error on the source element when the
the failure happened while processing one. Only call nonSupported() when the failure happened
while processing media element 'src' attribute.
(WebCore::HTMLMediaElement::havePotentialSourceChild): nextSourceChild -> selectNextSourceChild.
Deal with selectNextSourceChild returning a KURL instead of a String.
(WebCore::HTMLMediaElement::selectNextSourceChild): Renamed from nextSourceChild, add optional
param to control whether or not errors are fired on a source element when it will not be used.
Check safety of url here instead of waiting until loadResource(). Return a KURL instead of a
String.
(WebCore::HTMLMediaElement::initialURL): nextSourceChild -> selectNextSourceChild. Keep url as
a KURL instead of a String.
* html/HTMLMediaElement.h:
(WebCore::HTMLMediaElement::):
* html/HTMLSourceElement.cpp:
(WebCore::HTMLSourceElement::HTMLSourceElement): Initialize timer related variables.
(WebCore::HTMLSourceElement::scheduleErrorEvent): New, start one-shot timer to fire an error
event ASAP.
(WebCore::HTMLSourceElement::cancelPendingErrorEvent): New, cancel pending error event.
(WebCore::HTMLSourceElement::errorEventTimerFired): New, fire error event if it has not been
cancelled.
* html/HTMLSourceElement.h:
* html/MediaError.h:
(WebCore::MediaError::): MEDIA_ERR_NONE_SUPPORTED -> MEDIA_ERR_SRC_NOT_SUPPORTED
* html/MediaError.idl: Ditto
2009-05-08 Dan Bernstein <mitz@apple.com>
Reviewed by Maciej Stachowiak.
......@@ -244,7 +244,7 @@ void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
void HTMLMediaElement::enqueueEvent(RefPtr<Event> event)
{
m_pendingEvents.append(event);
if (!m_asyncEventTimer.isActive())
if (!m_asyncEventTimer.isActive())
m_asyncEventTimer.startOneShot(0);
}
......@@ -375,7 +375,7 @@ void HTMLMediaElement::loadInternal()
// 3 - If there are any tasks from the media element's media element event task source in
// one of the task queues, then remove those tasks.
m_pendingEvents.clear();
cancelPendingEventsAndCallbacks();
// 4 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, set the
// error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED,
......@@ -446,9 +446,13 @@ void HTMLMediaElement::selectMediaResource()
// 5 - If the media element has a src attribute, then run these substeps
ContentType contentType("");
if (!mediaSrc.isEmpty()) {
mediaSrc = document()->completeURL(mediaSrc).string();
m_loadState = LoadingFromSrcAttr;
loadResource(mediaSrc, contentType);
KURL mediaURL = document()->completeURL(mediaSrc);
if (isSafeToLoadURL(mediaURL, Complain)) {
m_loadState = LoadingFromSrcAttr;
loadResource(mediaURL, contentType);
} else
noneSupported();
return;
}
......@@ -460,36 +464,21 @@ void HTMLMediaElement::selectMediaResource()
void HTMLMediaElement::loadNextSourceChild()
{
ContentType contentType("");
String mediaSrc;
mediaSrc = nextSourceChild(&contentType);
if (mediaSrc.isEmpty()) {
noneSupported();
KURL mediaURL = selectNextSourceChild(&contentType, Complain);
if (!mediaURL.isValid()) {
// It seems wrong to fail silently when we give up because no suitable <source>
// element can be found and set the error attribute if the element's 'src' attribute
// fails, but that is what the spec says.
return;
}
m_loadState = LoadingFromSourceElement;
loadResource(mediaSrc, contentType);
loadResource(mediaURL, contentType);
}
void HTMLMediaElement::loadResource(String url, ContentType& contentType)
void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
{
Frame* frame = document()->frame();
FrameLoader* loader = frame ? frame->loader() : 0;
// don't allow remote to local urls
if (!loader || !loader->canLoad(KURL(KURL(), url), String(), document())) {
FrameLoader::reportLocalLoadFailed(frame, url);
// If we rejected the url from a <source> element and there are more <source> children, schedule
// the next one without reporting an error
if (m_loadState == LoadingFromSourceElement && havePotentialSourceChild())
scheduleLoad();
else
noneSupported();
return;
}
ASSERT(isSafeToLoadURL(url, Complain));
// The resource fetch algorithm
m_networkState = NETWORK_LOADING;
......@@ -515,6 +504,21 @@ void HTMLMediaElement::loadResource(String url, ContentType& contentType)
renderer()->updateFromElement();
}
bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
{
Frame* frame = document()->frame();
FrameLoader* loader = frame ? frame->loader() : 0;
// don't allow remote to local urls
if (!loader || !loader->canLoad(url, String(), document())) {
if (actionIfInvalid == Complain)
FrameLoader::reportLocalLoadFailed(frame, url.string());
return false;
}
return true;
}
void HTMLMediaElement::startProgressEventTimer()
{
if (m_progressEventTimer.isActive())
......@@ -534,8 +538,8 @@ void HTMLMediaElement::noneSupported()
// 3 - Reaching this step indicates that either the URL failed to resolve, or the media
// resource failed to load. Set the error attribute to a new MediaError object whose
// code attribute is set to MEDIA_ERR_NONE_SUPPORTED.
m_error = MediaError::create(MediaError::MEDIA_ERR_NONE_SUPPORTED);
// code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
// 4- Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
m_networkState = NETWORK_NO_SOURCE;
......@@ -580,6 +584,16 @@ void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
}
void HTMLMediaElement::cancelPendingEventsAndCallbacks()
{
m_pendingEvents.clear();
for (Node* node = firstChild(); node; node = node->nextSibling()) {
if (node->hasTagName(sourceTag))
static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
}
}
void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
{
beginProcessingMediaPlayerCallback();
......@@ -599,9 +613,11 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
stopPeriodicTimers();
// If we failed while trying to load a <source> element, the movie was never parsed, and there are more
// <source> children, schedule the next one without reporting an error
if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement && havePotentialSourceChild()) {
scheduleLoad();
// <source> children, schedule the next one
if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
m_currentSourceNode->scheduleErrorEvent();
if (havePotentialSourceChild())
scheduleLoad();
return;
}
......@@ -609,7 +625,7 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
else if (state == MediaPlayer::DecodeError)
mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
else if (state == MediaPlayer::FormatError)
else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr)
noneSupported();
if (isVideo())
......@@ -1113,55 +1129,65 @@ bool HTMLMediaElement::havePotentialSourceChild()
{
// Stash the current <source> node so we can restore it after checking
// to see there is another potential
Node* currentSourceNode = m_currentSourceNode;
String nextUrl = nextSourceChild();
HTMLSourceElement* currentSourceNode = m_currentSourceNode;
KURL nextURL = selectNextSourceChild(0, DoNothing);
m_currentSourceNode = currentSourceNode;
return !nextUrl.isEmpty();
return nextURL.isValid();
}
String HTMLMediaElement::nextSourceChild(ContentType *contentType)
KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
{
String mediaSrc;
KURL mediaURL;
Node* node;
bool lookingForPreviousNode = m_currentSourceNode;
bool canUse = false;
for (Node* node = firstChild(); node; node = node->nextSibling()) {
for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
if (!node->hasTagName(sourceTag))
continue;
if (lookingForPreviousNode) {
if (m_currentSourceNode == node)
if (m_currentSourceNode == static_cast<HTMLSourceElement*>(node))
lookingForPreviousNode = false;
continue;
}
HTMLSourceElement* source = static_cast<HTMLSourceElement*>(node);
if (!source->hasAttribute(srcAttr))
continue;
goto check_again;
if (source->hasAttribute(mediaAttr)) {
MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
if (!screenEval.eval(media.get()))
continue;
if (!screenEval.eval(media.get()))
goto check_again;
}
if (source->hasAttribute(typeAttr)) {
ContentType type(source->type());
if (!MediaPlayer::supportsType(type))
continue;
// return type with all parameters in place so the media engine can use them
if (contentType)
*contentType = type;
if (source->hasAttribute(typeAttr)) {
if (!MediaPlayer::supportsType(ContentType(source->type())))
goto check_again;
}
mediaSrc = source->src().string();
m_currentSourceNode = node;
break;
}
if (!mediaSrc.isEmpty())
mediaSrc = document()->completeURL(mediaSrc).string();
// Is it safe to load this url?
mediaURL = source->src();
if (!mediaURL.isValid() || !isSafeToLoadURL(mediaURL, actionIfInvalid))
goto check_again;
// Making it this far means the <source> looks reasonable
canUse = true;
if (contentType)
*contentType = ContentType(source->type());
return mediaSrc;
check_again:
if (!canUse && actionIfInvalid == Complain)
source->scheduleErrorEvent();
m_currentSourceNode = static_cast<HTMLSourceElement*>(node);
}
if (!canUse)
m_currentSourceNode = 0;
return canUse ? mediaURL : KURL();
}
void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
......@@ -1491,15 +1517,12 @@ void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
String HTMLMediaElement::initialURL()
{
String initialSrc = mediaSrc = getAttribute(srcAttr);
KURL initialSrc = document()->completeURL(getAttribute(srcAttr));
if (initialSrc.isEmpty())
initialSrc = nextSourceChild();
if (!initialSrc.isEmpty())
initialSrc = document()->completeURL(initialSrc).string();
if (!initialSrc.isValid())
initialSrc = selectNextSourceChild(0, DoNothing).string();
m_currentSrc = initialSrc;
m_currentSrc = initialSrc.string();
return initialSrc;
}
......
......@@ -39,6 +39,7 @@
namespace WebCore {
class Event;
class HTMLSourceElement;
class MediaError;
class KURL;
class TimeRanges;
......@@ -178,13 +179,17 @@ private:
// loading
void selectMediaResource();
void loadResource(String url, ContentType& contentType);
void loadResource(const KURL&, ContentType&);
void loadNextSourceChild();
void userCancelledLoad();
String nextSourceChild(ContentType* contentType = 0);
bool havePotentialSourceChild();
void noneSupported();
void mediaEngineError(PassRefPtr<MediaError> err);
void cancelPendingEventsAndCallbacks();
enum InvalidSourceAction { DoNothing, Complain };
bool isSafeToLoadURL(const KURL&, InvalidSourceAction);
KURL selectNextSourceChild(ContentType*, InvalidSourceAction);
// These "internal" functions do not check user gesture restrictions.
void loadInternal();
......@@ -243,7 +248,7 @@ protected:
// loading state
enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement };
LoadState m_loadState;
Node *m_currentSourceNode;
HTMLSourceElement *m_currentSourceNode;
OwnPtr<MediaPlayer> m_player;
......
......@@ -28,6 +28,7 @@
#if ENABLE(VIDEO)
#include "HTMLSourceElement.h"
#include "EventNames.h"
#include "HTMLDocument.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
......@@ -40,6 +41,7 @@ using namespace HTMLNames;
HTMLSourceElement::HTMLSourceElement(const QualifiedName& tagName, Document* doc)
: HTMLElement(tagName, doc)
, m_errorEventTimer(this, &HTMLSourceElement::errorEventTimerFired)
{
ASSERT(hasTagName(sourceTag));
}
......@@ -88,5 +90,23 @@ void HTMLSourceElement::setType(const String& type)
setAttribute(typeAttr, type);
}
void HTMLSourceElement::scheduleErrorEvent()
{
if (m_errorEventTimer.isActive())
return;
m_errorEventTimer.startOneShot(0);
}
void HTMLSourceElement::cancelPendingErrorEvent()
{
m_errorEventTimer.stop();
}
void HTMLSourceElement::errorEventTimerFired(Timer<HTMLSourceElement>*)
{
dispatchEvent(eventNames().errorEvent, false, true);
}
}
#endif
......@@ -29,6 +29,7 @@
#if ENABLE(VIDEO)
#include "HTMLElement.h"
#include "Timer.h"
#include <limits>
namespace WebCore {
......@@ -51,6 +52,14 @@ public:
void setSrc(const String&);
void setMedia(const String&);
void setType(const String&);
void scheduleErrorEvent();
void cancelPendingErrorEvent();
private:
void errorEventTimerFired(Timer<HTMLSourceElement>*);
Timer<HTMLSourceElement> m_errorEventTimer;
};
} //namespace
......
......@@ -34,7 +34,7 @@ namespace WebCore {
class MediaError : public RefCounted<MediaError> {
public:
enum Code { MEDIA_ERR_ABORTED = 1, MEDIA_ERR_NETWORK, MEDIA_ERR_DECODE, MEDIA_ERR_NONE_SUPPORTED };
enum Code { MEDIA_ERR_ABORTED = 1, MEDIA_ERR_NETWORK, MEDIA_ERR_DECODE, MEDIA_ERR_SRC_NOT_SUPPORTED };
static PassRefPtr<MediaError> create(Code code) { return adoptRef(new MediaError(code)); }
......
......@@ -28,7 +28,7 @@ module html {
const unsigned short MEDIA_ERR_ABORTED = 1;
const unsigned short MEDIA_ERR_NETWORK = 2;
const unsigned short ME