Bug 462455. Initiate media load when appending <source> child elements to media elements. r=doublec,sr=roc

--HG--
extra : rebase_source : b9bca050ef528705c08988d3677bf9bd8c865f33
This commit is contained in:
Chris Pearce 2009-02-16 14:05:28 +13:00
Родитель dc2eb3467f
Коммит 318f45146f
10 изменённых файлов: 394 добавлений и 49 удалений

Просмотреть файл

@ -154,8 +154,8 @@ inline nsINode* NODE_FROM(C& aContent, D& aDocument)
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0x355cc896, 0x2ed0, 0x4237, \
{ 0x85, 0xf7, 0x4d, 0xb0, 0xcf, 0x4d, 0xc4, 0x90 } }
{ 0x075803c5, 0xb37f, 0x489f, \
{ 0x9b, 0x17, 0x9a, 0x60, 0x44, 0x5d, 0x66, 0x1b } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
@ -215,7 +215,9 @@ public:
returns a non-null value for nsIContent::GetText() */
eDATA_NODE = 1 << 12,
/** nsMathMLElement */
eMATHML = 1 << 13
eMATHML = 1 << 13,
/** nsHTMLMediaElement */
eMEDIA = 1 << 14
};
/**

Просмотреть файл

@ -39,6 +39,7 @@
#include "nsGenericHTMLElement.h"
#include "nsMediaDecoder.h"
#include "nsIChannel.h"
#include "nsThreadUtils.h"
// Define to output information on decoding and painting framerate
/* #define DEBUG_FRAME_RATE 1 */
@ -46,6 +47,17 @@
typedef PRUint16 nsMediaNetworkState;
typedef PRUint16 nsMediaReadyState;
// Object representing a single execution of the media load algorithm.
// Used by implicit load events so that they can be cancelled when Load()
// is executed.
// Note: When bug 465458 lands, all events are expected to do this, not
// just implicit load events.
class nsMediaLoad : public nsISupports
{
public:
NS_DECL_ISUPPORTS;
};
class nsHTMLMediaElement : public nsGenericHTMLElement
{
public:
@ -192,6 +204,29 @@ public:
*/
static void ShutdownMediaTypes();
/**
* Called when a child source element is added to this media element. This
* may queue a load() task if appropriate.
*/
void NotifyAddedSource();
virtual PRBool IsNodeOfType(PRUint32 aFlags) const;
/**
* Queues an event to call Load().
*/
void QueueLoadTask();
/**
* Returns the current nsMediaLoad object. Implicit load events store a
* reference to the nsMediaLoad object that was current when they were
* enqueued, and if it has changed when they come to fire, they consider
* themselves cancelled, and don't fire.
* Note: When bug 465458 lands, all events are expected to do this, not
* just implicit load events.
*/
nsMediaLoad* GetCurrentMediaLoad() { return mCurrentLoad; }
protected:
class nsMediaLoadListener;
@ -235,6 +270,9 @@ protected:
// Error attribute
nsCOMPtr<nsIDOMHTMLMediaError> mError;
// The current media load object.
nsRefPtr<nsMediaLoad> mCurrentLoad;
// Media loading flags. See:
// http://www.whatwg.org/specs/web-apps/current-work/#video)
nsMediaNetworkState mNetworkState;
@ -291,4 +329,7 @@ protected:
// PR_TRUE if we've reported a "waiting" event since the last
// readyState change to HAVE_CURRENT_DATA.
PRPackedBool mWaitingFired;
// PR_TRUE if we're in BindToTree().
PRPackedBool mIsBindingToTree;
};

Просмотреть файл

@ -103,6 +103,26 @@ public:
}
};
// Asynchronous runner which invokes Load() on the main thread.
class nsMediaLoadEvent : public nsRunnable
{
public:
nsMediaLoadEvent(nsHTMLMediaElement *aMedia)
: mMedia(aMedia), mCurrentLoad(mMedia->GetCurrentMediaLoad()) {}
~nsMediaLoadEvent() {}
NS_IMETHOD Run() {
// Only run the task if it's not been cancelled.
if (mMedia && mMedia->GetCurrentMediaLoad() == mCurrentLoad)
mMedia->Load();
return NS_OK;
}
private:
nsCOMPtr<nsHTMLMediaElement> mMedia;
nsRefPtr<nsMediaLoad> mCurrentLoad;
};
class nsHTMLMediaElement::nsMediaLoadListener : public nsIStreamListener
{
NS_DECL_ISUPPORTS
@ -169,6 +189,8 @@ NS_IMETHODIMP nsHTMLMediaElement::nsMediaLoadListener::OnDataAvailable(nsIReques
return mNextListener->OnDataAvailable(aRequest, aContext, aStream, aOffset, aCount);
}
NS_IMPL_ISUPPORTS0(nsMediaLoad)
// nsIDOMHTMLMediaElement
NS_IMPL_URI_ATTR(nsHTMLMediaElement, Src, src)
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Controls, controls)
@ -257,9 +279,21 @@ void nsHTMLMediaElement::NoSupportedMediaError()
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied"));
}
void nsHTMLMediaElement::QueueLoadTask()
{
nsCOMPtr<nsIRunnable> event = new nsMediaLoadEvent(this);
NS_DispatchToMainThread(event);
}
/* void load (); */
NS_IMETHODIMP nsHTMLMediaElement::Load()
{
// Set a new load object. This will cause implicit load events which were
// enqueued before with a different load object to silently be cancelled.
// Note: When bug 465458 lands, all events are expected to do this, not
// just implicit load events.
mCurrentLoad = new nsMediaLoad();
if (AbortExistingLoads())
return NS_OK;
@ -271,7 +305,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
nsresult rv = PickMediaElement(getter_AddRefs(uri));
if (NS_FAILED(rv)) {
NoSupportedMediaError();
return rv;
return NS_OK;
}
if (mChannel) {
@ -291,7 +325,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
nsContentUtils::GetSecurityManager());
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
NoSupportedMediaError();
return NS_ERROR_CONTENT_BLOCKED;
return NS_OK;
}
rv = NS_NewChannel(getter_AddRefs(mChannel),
@ -302,7 +336,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
nsIRequest::LOAD_NORMAL);
if (NS_FAILED(rv)) {
NetworkError();
return rv;
return NS_OK;
}
// The listener holds a strong reference to us. This creates a reference
// cycle which is manually broken in the listener's OnStartRequest method
@ -320,7 +354,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
if (NS_FAILED(rv)) {
NoSupportedMediaError();
return rv;
return NS_OK;
}
} else {
rv = nsContentUtils::GetSecurityManager()->
@ -329,7 +363,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
nsIScriptSecurityManager::STANDARD);
if (NS_FAILED(rv)) {
NoSupportedMediaError();
return rv;
return NS_OK;
}
listener = loadListener;
}
@ -354,7 +388,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
// be destroyed.
mChannel = nsnull;
NetworkError();
return rv;
return NS_OK;
}
return NS_OK;
@ -530,7 +564,8 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
mMuted(PR_FALSE),
mIsDoneAddingChildren(!aFromParser),
mPlayingBeforeSeek(PR_FALSE),
mWaitingFired(PR_FALSE)
mWaitingFired(PR_FALSE),
mIsBindingToTree(PR_FALSE)
{
}
@ -630,17 +665,19 @@ nsresult nsHTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aPar
nsIContent* aBindingParent,
PRBool aCompileEventHandlers)
{
mIsBindingToTree = PR_TRUE;
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument,
aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
if (mIsDoneAddingChildren &&
if (NS_SUCCEEDED(rv) &&
mIsDoneAddingChildren &&
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
Load();
QueueLoadTask();
}
mIsBindingToTree = PR_FALSE;
return rv;
}
@ -1229,7 +1266,7 @@ nsresult nsHTMLMediaElement::DoneAddingChildren(PRBool aHaveNotified)
mIsDoneAddingChildren = PR_TRUE;
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
Load();
QueueLoadTask();
}
}
@ -1310,3 +1347,25 @@ void nsHTMLMediaElement::Thaw()
mDecoder->Resume();
}
}
PRBool
nsHTMLMediaElement::IsNodeOfType(PRUint32 aFlags) const
{
return !(aFlags & ~(eCONTENT | eELEMENT | eHTML | eMEDIA));
}
void nsHTMLMediaElement::NotifyAddedSource()
{
// Binding a source element to a media element could trigger a new load.
// See HTML spec, '4.8.9 The source element' for conditions:
// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
// Note: we must not start a load if we're in nsHTMLMediaElement::BindToTree(),
// that will trigger a load when it completes.
PRBool shouldLoad = IsInDoc() &&
!mIsBindingToTree &&
mIsDoneAddingChildren &&
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY;
if (shouldLoad) {
QueueLoadTask();
}
}

Просмотреть файл

@ -43,6 +43,9 @@
#include "nsPresContext.h"
#include "nsMappedAttributes.h"
#include "nsRuleData.h"
#include "nsHTMLMediaElement.h"
#include "nsCOMPtr.h"
#include "nsThreadUtils.h"
class nsHTMLSourceElement : public nsGenericHTMLElement,
public nsIDOMHTMLSourceElement
@ -71,6 +74,12 @@ public:
const nsAString& aValue,
nsAttrValue& aResult);
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
// Override BindToTree() so that we can trigger a load when we add a
// child source element.
virtual nsresult BindToTree(nsIDocument *aDocument, nsIContent *aParent,
nsIContent *aBindingParent,
PRBool aCompileEventHandlers);
};
@ -124,3 +133,24 @@ nsHTMLSourceElement::ParseAttribute(PRInt32 aNamespaceID,
aResult);
}
nsresult
nsHTMLSourceElement::BindToTree(nsIDocument *aDocument,
nsIContent *aParent,
nsIContent *aBindingParent,
PRBool aCompileEventHandlers)
{
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument,
aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
if (!aParent->IsNodeOfType(nsINode::eMEDIA))
return NS_OK;
nsHTMLMediaElement* media = static_cast<nsHTMLMediaElement*>(aParent);
media->NotifyAddedSource();
return NS_OK;
}

Просмотреть файл

@ -178,6 +178,13 @@ public:
nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus();
private:
// Returns PR_TRUE if we're in shutdown state. Threadsafe.
PRBool IsShutdown();
// Reads from the media stream. Returns PR_FALSE on failure or EOF.
PRBool ReadAll(char* aBuf, PRUint32 aSize);
// Change the current state and wake the playback thread if it is waiting
// on mMonitor. Used by public member functions called from both threads,
// so must hold mMonitor. Threadsafe.
@ -898,16 +905,25 @@ ReadUint16LE(const char** aBuffer)
return result;
}
static PRBool
ReadAll(nsMediaStream* aStream, char* aBuf, PRUint32 aSize)
PRBool
nsWaveStateMachine::IsShutdown()
{
nsAutoMonitor monitor(mMonitor);
return mState == STATE_SHUTDOWN;
}
PRBool
nsWaveStateMachine::ReadAll(char* aBuf, PRUint32 aSize)
{
PRUint32 got = 0;
do {
PRUint32 read = 0;
if (NS_FAILED(aStream->Read(aBuf + got, aSize - got, &read))) {
if (NS_FAILED(mStream->Read(aBuf + got, aSize - got, &read))) {
NS_WARNING("Stream read failed");
return PR_FALSE;
}
if (IsShutdown())
return PR_FALSE;
got += read;
} while (got != aSize);
return PR_TRUE;
@ -922,7 +938,7 @@ nsWaveStateMachine::LoadRIFFChunk()
NS_ABORT_IF_FALSE(mStream->Tell() == 0,
"LoadRIFFChunk called when stream in invalid state");
if (!ReadAll(mStream, riffHeader, sizeof(riffHeader))) {
if (!ReadAll(riffHeader, sizeof(riffHeader))) {
return PR_FALSE;
}
@ -953,7 +969,7 @@ nsWaveStateMachine::LoadFormatChunk()
NS_ABORT_IF_FALSE(mStream->Tell() % 2 == 0,
"LoadFormatChunk called with unaligned stream");
if (!ReadAll(mStream, waveFormat, sizeof(waveFormat))) {
if (!ReadAll(waveFormat, sizeof(waveFormat))) {
return PR_FALSE;
}
@ -988,7 +1004,7 @@ nsWaveStateMachine::LoadFormatChunk()
char extLength[2];
const char* p = extLength;
if (!ReadAll(mStream, extLength, sizeof(extLength))) {
if (!ReadAll(extLength, sizeof(extLength))) {
return PR_FALSE;
}
@ -1001,7 +1017,7 @@ nsWaveStateMachine::LoadFormatChunk()
if (extra > 0) {
nsAutoArrayPtr<char> chunkExtension(new char[extra]);
if (!ReadAll(mStream, chunkExtension.get(), extra)) {
if (!ReadAll(chunkExtension.get(), extra)) {
return PR_FALSE;
}
}
@ -1050,7 +1066,7 @@ nsWaveStateMachine::FindDataOffset()
char chunkHeader[8];
const char* p = chunkHeader;
if (!ReadAll(mStream, chunkHeader, sizeof(chunkHeader))) {
if (!ReadAll(chunkHeader, sizeof(chunkHeader))) {
return PR_FALSE;
}
@ -1070,7 +1086,7 @@ nsWaveStateMachine::FindDataOffset()
size += size % 2;
nsAutoArrayPtr<char> chunk(new char[size]);
if (!ReadAll(mStream, chunk.get(), size)) {
if (!ReadAll(chunk.get(), size)) {
return PR_FALSE;
}
}

Просмотреть файл

@ -76,9 +76,12 @@ _TEST_FILES += \
test_ended2.html \
test_error_on_404.html \
test_onloadedmetadata.html \
test_load_coalescing.html \
test_play.html \
test_progress1.html \
test_progress3.html \
test_source.html \
test_source_write.html \
test_standalone.html \
test_timeupdate1.html \
test_timeupdate2.html \

Просмотреть файл

@ -0,0 +1,102 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=462455
-->
<head>
<title>Test for Bug 462455</title>
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<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=462455">Mozilla Bug 462455</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 462455 **/
/** Tests case described in bug 462455 comment 22. **/
var gLoadStartsCount = 0;
var gAbortCount = 0;
var gVolumeChanged = 0;
var gEmptiedCount = 0;
function errorHandler(e) {
e.stopPropagation();
}
function abortHandler() {
gAbortCount++;
}
function startHandler() {
gLoadStartsCount++;
}
function loadedHandler() {
is(gLoadStartsCount, 2, "Should have received 2 loadstarts.");
is(gAbortCount, 0, "Shouldn't have aborted any loads");
is(gVolumeChanged, 1, "Should have received volume changed");
is(gEmptiedCount, 1, "EmptiedCount should be 1");
gLoadStartsCount = 0;
gAbortCount = 0;
SimpleTest.finish();
}
function emptiedHandler() {
gEmptiedCount++;
}
function volumeChangeHandler() {
gVolumeChanged++;
}
function testEventOrder() {
var v = document.createElement('video');
v.addEventListener('error', errorHandler, false);
v.addEventListener('abort', abortHandler, false);
v.addEventListener('loadeddata', loadedHandler, false);
v.addEventListener('loadstart', startHandler, false);
v.addEventListener('volumechange', volumeChangeHandler, false);
v.addEventListener('emptied', emptiedHandler, false);
document.body.appendChild(v); // Queues implicit load. This should be silently cancelled by the next explicit load.
var s = document.createElement("source");
s.type = "bogus/type";
s.src = "error-404.ogv";
v.appendChild(s); // Will queue a load. This should be silently cancelled by the next explicit load.
v.load(); // Explicit load. Will cancel queued loads. Expect loadstart, emptied, error events.
v.muted = true; // Will queue a volumechanged event.
// Load continues in background asynchronously.
v.addEventListener('error',
function (event) {
event.stopPropagation();
var s2 = document.createElement("source");
s2.type = "application/ogg";
s2.src = "320x240.ogv";
v.appendChild(s2); // Will queue a load. Expect loadstart, loadeddata etc.
// Should coalesce with the previous load, so there should be 1 load, and volume changed should arrive first.
}, false);
// First two implicit loads will run and silently cancel themselves some time after this function returns. Expect no events.
// Then the volumechange event should run.
// Then the third implicit load (for s2) should run and succeed. Expect loadstart and loadeddata events.
}
addLoadEvent(testEventOrder);
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -14,33 +14,32 @@ SimpleTest.waitForExplicitFinish();
function maketest(expect_load, attach_media, name, type, check_metadata) {
return function (testNum) {
var e = document.createElement('video');
e.addEventListener('error', function(e) { e.stopPropagation();}, false);
var errorRun = false;
if (expect_load) {
// this could be loadedmetadata, but needs bug 466410 fixed
e.addEventListener('loadeddata', function () {
e.addEventListener('loadedmetadata', function () {
ok(e.readyState >= HTMLMediaElement.HAVE_METADATA,
'test ' + testNum + ' networkState ' + e.networkState + ' expected >= ' + e.LOADED_METADATA);
'test ' + testNum + ' readyState ' + e.readyState + ' expected >= ' + HTMLMediaElement.HAVE_METADATA);
is(e.currentSrc.substring(e.currentSrc.length - name.length), name, 'test ' + testNum);
ok(e.networkState >= HTMLMediaElement.NETWORK_LOADING,
'test ' + testNum + ' networkState = ' + e.networkState + ' expected >= ' + HTMLMediaElement.NETWORK_LOADING);
check_metadata(e);
e.parentNode.removeChild(e);
runNextTest();
}, false);
}
attach_media(e, name, type);
if (expect_load) {
ok(e.networkState >= HTMLMediaElement.NETWORK_LOADING,
'test ' + testNum + ' networkState ' + e.networkState + ' expected >= ' + e.LOADING);
e.addEventListener('error', function(e) { e.stopPropagation();}, false);
} else {
ok(e.networkState == HTMLMediaElement.NETWORK_EMPTY,
'test ' + testNum + ' networkState ' + e.networkState + ' expected ' + e.EMPTY);
is(e.currentSrc, '', 'test ' + testNum);
e.parentNode.removeChild(e);
runNextTest();
}
e.addEventListener('error', function(event) {
event.stopPropagation();
is(expect_load, false, "Didn't load when we weren't expecting to.");
is(errorRun, false, "error handler should run once only!");
errorRun = true;
is(e.readyState, HTMLMediaElement.HAVE_NOTHING,
'test ' + testNum + ' readyState should be HAVE_NOTHING when load fails.');
e.parentNode.removeChild(e);
runNextTest();
}, false);
}
attach_media(e, name, type);
}
}
@ -119,14 +118,14 @@ var subTests = [
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),
maketest(false, add_source, 'unknown.raw', 'application/ogg', null),
maketest(false, 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.ogv', null, 0.2, 0.4),
// maketest(true, late_add_sources_first, '320x240.ogv', '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),
maketest(true, late_add_sources_last, '320x240.ogv', 'application/ogg', check_ogg),
maketest(true, late_add_sources_first, '320x240.ogv', 'application/ogg', check_ogg),
maketest(true, late_add_sources_last, 'r11025_u8_c1.wav', 'audio/x-wav', check_wav),
maketest(true, late_add_sources_first, 'r11025_u8_c1.wav', 'audio/x-wav', check_wav),
SimpleTest.finish
];

Просмотреть файл

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Media test: append source child</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>
<video id="v1" onerror="event.stopPropagation();"></video>
<audio id="a1" onerror="event.stopPropagation();"></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
var v1 = document.getElementById("v1");
var a1 = document.getElementById("a1");
is(v1.src, "", "src should be null");
is(a1.src, "", "src should be null");
is(v1.currentSrc, "", "currentSrc should be null");
is(a1.currentSrc, "", "currentSrc should be null");
is(v1.childNodes.length, 0, "should have no children");
is(a1.childNodes.length, 0, "should have no children");
function newSource() {
var e = document.createElement("source");
e.type = "application/ogg";
e.src = "320x240.ogv";
return e;
}
var audioLoaded = false;
var videoLoaded = false;
function loaded(media) {
ok(media.networkState > 0, "networkState should be > 0");
is(media.childNodes.length, 1, "should have 1 child");
var sourceFile = media.currentSrc.substring(media.currentSrc.lastIndexOf('/'));
is(sourceFile, "/320x240.ogv", "loaded wrong resource");
if (media == a1)
audioLoaded = true;
else if (media == v1)
videoLoaded = true;
if (audioLoaded && videoLoaded) {
SimpleTest.finish();
}
}
v1.addEventListener('loadeddata', function() { loaded(v1); }, false);
a1.addEventListener('loadeddata', function() { loaded(a1); }, false);
v1.appendChild(newSource());
a1.appendChild(newSource());
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,35 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=462455
-->
<head>
<title>Test for Bug 462455</title>
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<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=462455">Mozilla Bug 462455</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<video id="v">
<source src="320x240.ogv" type="application/ogg"></source>
<script>
var loadStarted = false;
document.write('Pause parsing!');
var v = document.getElementById('v');
if (v.networkState != HTMLMediaElement.NETWORK_EMPTY) {
loadStarted = true;
}
is(loadStarted, false, "We shouldn't start a load until the video tag is closed.");
</script>
</video>
</body>
</html>