Backed out changeset 3f5a6da199fc

This commit is contained in:
Robert O'Callahan 2008-12-03 13:26:55 +13:00
parent d483c98f06
commit eac60f52ac
5 changed files with 78 additions and 390 deletions

View File

@ -173,15 +173,19 @@ public:
protected:
/**
* Figure out which resource to load (either the 'src' attribute or a
* <source> child) and return the associated URI.
* Figure out which resource to load (either the 'src' attribute or
* a <source> child) and create the decoder for it.
*/
nsresult PickMediaElement(nsIURI** aURI);
nsresult PickMediaElement();
/**
* Create a decoder for the given aMIMEType. Returns false if we
* were unable to create the decoder.
*/
PRBool CreateDecoder(const nsACString& aMIMEType);
/**
* Initialize a decoder to load the given URI.
*/
nsresult InitializeDecoder(const nsAString& aURISpec);
/**
* Initialize a decoder to load the given channel. The decoder's stream
* listener is returned via aListener.
@ -189,15 +193,8 @@ protected:
nsresult InitializeDecoderForChannel(nsIChannel *aChannel,
nsIStreamListener **aListener);
/**
* Create a URI for the given aURISpec string.
*/
nsresult NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI);
nsRefPtr<nsMediaDecoder> mDecoder;
nsCOMPtr<nsIChannel> mChannel;
// Error attribute
nsCOMPtr<nsIDOMHTMLMediaError> mError;

View File

@ -96,64 +96,6 @@ public:
}
};
class nsMediaLoadListener : public nsIStreamListener
{
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
public:
nsMediaLoadListener(nsHTMLMediaElement* aElement)
: mElement(aElement)
{
NS_ABORT_IF_FALSE(mElement, "Must pass an element to call back");
}
private:
nsRefPtr<nsHTMLMediaElement> mElement;
nsCOMPtr<nsIStreamListener> mNextListener;
};
NS_IMPL_ISUPPORTS2(nsMediaLoadListener, nsIRequestObserver, nsIStreamListener)
NS_IMETHODIMP nsMediaLoadListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
{
nsresult rv;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel &&
mElement &&
NS_SUCCEEDED(mElement->LoadWithChannel(channel, getter_AddRefs(mNextListener))) &&
mNextListener) {
rv = mNextListener->OnStartRequest(aRequest, aContext);
} else {
// If LoadWithChannel did not return a listener, we abort the connection
// since we aren't interested in keeping the channel alive ourselves.
rv = NS_BINDING_ABORTED;
}
// The element is only needed until we've had a chance to call
// LoadWithChannel.
mElement = nsnull;
return rv;
}
NS_IMETHODIMP nsMediaLoadListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
{
if (mNextListener) {
return mNextListener->OnStopRequest(aRequest, aContext, aStatus);
}
return NS_OK;
}
NS_IMETHODIMP nsMediaLoadListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
nsIInputStream* aStream, PRUint32 aOffset, PRUint32 aCount)
{
NS_ABORT_IF_FALSE(mNextListener, "Must have a listener");
return mNextListener->OnDataAvailable(aRequest, aContext, aStream, aOffset, aCount);
}
// nsIDOMHTMLMediaElement
NS_IMPL_URI_ATTR(nsHTMLMediaElement, Src, src)
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Controls, controls)
@ -211,69 +153,17 @@ NS_IMETHODIMP nsHTMLMediaElement::GetTotalBytes(PRUint32 *aTotalBytes)
/* void load (); */
NS_IMETHODIMP nsHTMLMediaElement::Load()
{
nsCOMPtr<nsIURI> uri;
nsresult rv = PickMediaElement(getter_AddRefs(uri));
if (NS_FAILED(rv))
return rv;
if (mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED);
mChannel = nsnull;
}
rv = NS_NewChannel(getter_AddRefs(mChannel),
uri,
nsnull,
nsnull,
nsnull,
nsIRequest::LOAD_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
// The listener holds a strong reference to us. This creates a reference
// cycle which is manually broken in the listener's OnStartRequest method
// after it is finished with the element.
nsCOMPtr<nsIStreamListener> listener = new nsMediaLoadListener(this);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(mChannel);
if (hc) {
// Use a byte range request from the start of the resource.
// This enables us to detect if the stream supports byte range
// requests, and therefore seeking, early.
hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"),
NS_LITERAL_CSTRING("bytes=0-"),
PR_FALSE);
}
rv = mChannel->AsyncOpen(listener, nsnull);
if (NS_FAILED(rv)) {
// OnStartRequest is guaranteed to be called if the open succeeds. If
// the open failed, the listener's OnStartRequest will never be called,
// so we need to break the element->channel->listener->element reference
// cycle here. The channel holds the only reference to the listener,
// and is useless now anyway, so drop our reference to it to allow it to
// be destroyed.
mChannel = nsnull;
return rv;
}
mNetworkState = nsIDOMHTMLMediaElement::LOADING;
return NS_OK;
return LoadWithChannel(nsnull, nsnull);
}
nsresult nsHTMLMediaElement::LoadWithChannel(nsIChannel *aChannel,
nsIStreamListener **aListener)
{
NS_ENSURE_ARG_POINTER(aChannel);
NS_ENSURE_ARG_POINTER(aListener);
NS_ASSERTION((aChannel == nsnull) == (aListener == nsnull),
"channel and listener should both be null or both non-null");
*aListener = nsnull;
if (mDecoder) {
mDecoder->ElementUnavailable();
mDecoder->Shutdown();
mDecoder = nsnull;
if (aListener) {
*aListener = nsnull;
}
if (mBegun) {
@ -299,10 +189,13 @@ nsresult nsHTMLMediaElement::LoadWithChannel(nsIChannel *aChannel,
DispatchSimpleEvent(NS_LITERAL_STRING("emptied"));
}
nsresult rv = InitializeDecoderForChannel(aChannel, aListener);
if (NS_FAILED(rv)) {
return rv;
nsresult rv;
if (aChannel) {
rv = InitializeDecoderForChannel(aChannel, aListener);
} else {
rv = PickMediaElement();
}
NS_ENSURE_SUCCESS(rv, rv);
mBegun = PR_TRUE;
mEnded = PR_FALSE;
@ -473,10 +366,6 @@ nsHTMLMediaElement::~nsHTMLMediaElement()
mDecoder->Shutdown();
mDecoder = nsnull;
}
if (mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED);
mChannel = nsnull;
}
}
NS_IMETHODIMP
@ -675,21 +564,6 @@ void nsHTMLMediaElement::ShutdownMediaTypes()
}
}
static PRBool CanDecode(const nsACString& aType)
{
#ifdef MOZ_OGG
if (IsOggType(aType)) {
return PR_TRUE;
}
#endif
#ifdef MOZ_WAVE
if (IsWaveType(aType)) {
return PR_TRUE;
}
#endif
return PR_FALSE;
}
PRBool nsHTMLMediaElement::CreateDecoder(const nsACString& aType)
{
#ifdef MOZ_OGG
@ -722,84 +596,81 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
mNetworkState = nsIDOMHTMLMediaElement::LOADING;
mDecoder->ElementAvailable(this);
return mDecoder->Load(nsnull, aChannel, aListener);
}
nsresult nsHTMLMediaElement::NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI)
nsresult nsHTMLMediaElement::PickMediaElement()
{
NS_ENSURE_ARG_POINTER(aURI);
// Implements:
// http://www.whatwg.org/specs/web-apps/current-work/#pick-a
nsAutoString src;
if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
#ifdef MOZ_OGG
// Currently assuming an Ogg file
// TODO: Instantiate decoder based on type
if (mDecoder) {
mDecoder->ElementUnavailable();
mDecoder->Shutdown();
mDecoder = nsnull;
}
*aURI = nsnull;
mDecoder = new nsOggDecoder();
if (mDecoder && !mDecoder->Init()) {
mDecoder = nsnull;
}
#endif
return InitializeDecoder(src);
}
// Checking of 'source' elements as per:
// http://www.whatwg.org/specs/web-apps/current-work/#pick-a
PRUint32 count = GetChildCount();
for (PRUint32 i = 0; i < count; ++i) {
nsIContent* child = GetChildAt(i);
NS_ASSERTION(child, "GetChildCount lied!");
nsCOMPtr<nsIContent> source = do_QueryInterface(child);
if (source) {
nsAutoString type;
nsAutoString src;
if (source->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src) &&
source->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type) &&
CreateDecoder(NS_ConvertUTF16toUTF8(type)))
return InitializeDecoder(src);
}
}
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsresult nsHTMLMediaElement::InitializeDecoder(const nsAString& aURISpec)
{
mNetworkState = nsIDOMHTMLMediaElement::LOADING;
nsCOMPtr<nsIDocument> doc = GetOwnerDoc();
if (!doc) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aURI,
aURISpec,
doc,
baseURI);
nsresult rv;
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIURI> baseURL = GetBaseURI();
rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
aURISpec,
doc,
baseURL);
NS_ENSURE_SUCCESS(rv, rv);
PRBool equal;
if (aURISpec.IsEmpty() &&
doc->GetDocumentURI() &&
NS_SUCCEEDED(doc->GetDocumentURI()->Equals(*aURI, &equal)) &&
equal) {
// It's not possible for a media resource to be embedded in the current
// document we extracted aURISpec from, so there's no point returning
// the current document URI just to let the caller attempt and fail to
// decode it.
NS_RELEASE(*aURI);
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
return NS_OK;
}
nsresult nsHTMLMediaElement::PickMediaElement(nsIURI** aURI)
{
NS_ENSURE_ARG_POINTER(aURI);
// Implements:
// http://www.whatwg.org/specs/web-apps/current-work/#pick-a-media-resource
nsAutoString src;
if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
return NewURIFromString(src, aURI);
}
// Checking of 'source' elements as per:
// http://www.whatwg.org/specs/web-apps/current-work/#pick-a-media-resource
PRUint32 count = GetChildCount();
for (PRUint32 i = 0; i < count; ++i) {
nsIContent* child = GetChildAt(i);
NS_ASSERTION(child, "GetChildCount lied!");
nsCOMPtr<nsIContent> source = do_QueryInterface(child);
if (source &&
source->Tag() == nsGkAtoms::source &&
source->IsNodeOfType(nsINode::eHTML)) {
nsAutoString type;
nsAutoString src;
if (source->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
if (source->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type)) {
if (CanDecode(NS_ConvertUTF16toUTF8(type))) {
return NewURIFromString(src, aURI);
}
} else if (i + 1 == count) {
// The last source element is permitted to omit the type
// attribute, in which case we need to open the URI and examine
// the channel's MIME type.
return NewURIFromString(src, aURI);
}
}
if (mDecoder) {
mDecoder->ElementAvailable(this);
rv = mDecoder->Load(uri, nsnull, nsnull);
if (NS_FAILED(rv)) {
mDecoder->Shutdown();
mDecoder = nsnull;
}
}
return NS_ERROR_DOM_INVALID_STATE_ERR;
return rv;
}
void nsHTMLMediaElement::MetadataLoaded()
@ -1016,10 +887,6 @@ void nsHTMLMediaElement::DestroyContent()
mDecoder->Shutdown();
mDecoder = nsnull;
}
if (mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED);
mChannel = nsnull;
}
nsGenericHTMLElement::DestroyContent();
}

View File

@ -45,14 +45,12 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES = test_autoplay.html \
test_bug461281.html \
test_bug463162.xhtml \
test_constants.html \
test_controls.html \
test_currentTime.html \
test_duration1.html \
test_ended1.html \
test_ended2.html \
test_media_selection.html \
test_networkState.html \
test_paused.html \
test_readyState.html \

View File

@ -1,31 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:svg="http://www.w3.org/2000/svg">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=463162
-->
<head>
<title>Test for Bug 463162</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"/>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=463162">Mozilla Bug 463162</a>
<audio id='a1'><sauce type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a2'><source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a3'><html:source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a4'><svg:source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
ok($("a1").networkState == HTMLMediaElement.EMPTY, "audio a1 with bogus child should not be loading");
ok($("a2").networkState >= HTMLMediaElement.LOADING, "audio a2 with valid child should be loading");
ok($("a3").networkState >= HTMLMediaElement.LOADING, "audio a3 with valid child should be loading");
ok($("a4").networkState == HTMLMediaElement.EMPTY, "audio a4 with bogus child should not be loading");
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,143 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Media test: media selection</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
function maketest(expect_load, attach_media, name, type, check_metadata) {
return function (testNum) {
var e = document.createElement('video');
if (expect_load) {
// this could be loadedmetadata, but needs bug 466410 fixed
e.addEventListener('loadedfirstframe', function () {
ok(e.networkState >= e.LOADED_METADATA,
'test ' + testNum + ' networkState ' + e.networkState + ' expected >= ' + e.LOADED_METADATA);
is(e.currentSrc.substring(e.currentSrc.length - name.length), name, 'test ' + testNum);
check_metadata(e);
e.parentNode.removeChild(e);
runNextTest();
}, false);
}
attach_media(e, name, type);
if (expect_load) {
ok(e.networkState >= e.LOADING,
'test ' + testNum + ' networkState ' + e.networkState + ' expected >= ' + e.LOADING);
} else {
ok(e.networkState == e.EMPTY,
'test ' + testNum + ' networkState ' + e.networkState + ' expected ' + e.EMPTY);
is(e.currentSrc, '', 'test ' + testNum);
e.parentNode.removeChild(e);
runNextTest();
}
}
}
function set_src(element, name, type) {
element.src = name;
document.body.appendChild(element);
}
function add_source(element, name, type) {
do_add_source(element, name, type);
document.body.appendChild(element);
}
function do_add_source(element, name, type) {
var source = document.createElement('source');
if (type) {
source.type = type;
}
source.src = name;
element.appendChild(source);
}
function add_sources_last(element, name, type) {
do_add_source(element, name, 'unsupported/type');
do_add_source(element, name, type);
document.body.appendChild(element);
}
function add_sources_first(element, name, type) {
do_add_source(element, name, type);
do_add_source(element, name, 'unsupported/type');
document.body.appendChild(element);
}
function late_add_sources_last(element, name, type) {
document.body.appendChild(element);
do_add_source(element, name, 'unsupported/type');
do_add_source(element, name, type);
}
function late_add_sources_first(element, name, type) {
document.body.appendChild(element);
do_add_source(element, name, type);
do_add_source(element, name, 'unsupported/type');
}
function check_ogg(e) {
ok(e.videoWidth == 320 && e.videoHeight == 240, "video should be 320x240");
}
function check_wav(e) {
ok(e.duration > 0.9 && e.duration < 1.1, "duration should be around 1.0");
}
var nextTest = 0;
var subTests = [
maketest(true, set_src, '320x240.ogg', null, check_ogg),
maketest(true, add_source, '320x240.ogg', null, check_ogg),
maketest(true, add_source, '320x240.ogg', 'application/ogg', check_ogg),
maketest(true, add_sources_last, '320x240.ogg', null, check_ogg),
maketest(true, add_sources_first, '320x240.ogg', 'application/ogg', check_ogg),
maketest(true, set_src, 'r11025_u8_c1.wav', null, check_wav),
maketest(true, add_source, 'r11025_u8_c1.wav', null, check_wav),
maketest(true, add_source, 'r11025_u8_c1.wav', 'audio/x-wav', check_wav),
maketest(true, add_sources_last, 'r11025_u8_c1.wav', null, check_wav),
maketest(true, add_sources_first, 'r11025_u8_c1.wav', 'audio/x-wav', check_wav),
// type hint matches a decoder, actual type matches different decoder
maketest(true, add_source, '320x240.ogg', 'audio/x-wav', check_ogg),
maketest(true, add_source, 'r11025_u8_c1.wav', 'application/ogg', check_wav),
// should not start loading, type excludes it from media candiate list
maketest(false, add_source, '320x240.ogg', 'bogus/type', null),
maketest(false, add_source, 'r11025_u8_c1.wav', 'bogus/type', null),
maketest(false, add_source, 'unknown.raw', 'bogus/type', null),
// should start loading, then fire error, needs bug 462455 fixed
// maketest(true, add_source, 'unknown.raw', 'application/ogg', null),
// maketest(true, add_source, 'unknown.raw', 'audio/x-wav', null),
// element doesn't notice source children attached later, needs bug 462455 fixed
// maketest(true, late_add_sources_last, '320x240.ogg', null, 0.2, 0.4),
// maketest(true, late_add_sources_first, '320x240.ogg', 'application/ogg', 0.2, 0.4),
// maketest(true, late_add_sources_last, 'r11025_u8_c1.wav', null, 0.2, 0.4),
// maketest(true, late_add_sources_first, 'r11025_u8_c1.wav', 'audio/x-wav', 0.2, 0.4),
SimpleTest.finish
];
function runNextTest() {
setTimeout(function () {
dump('subtest ' + nextTest + '\n');
subTests[nextTest](nextTest);
nextTest += 1;
}, 0);
}
addLoadEvent(runNextTest);
</script>
</pre>
</body>
</html>