зеркало из https://github.com/mozilla/pjs.git
Chris Pearce - Bug 479711 - Media elements should delay the document 'load' event
This commit is contained in:
Родитель
303c62ecb4
Коммит
37265832b0
|
@ -292,6 +292,12 @@ protected:
|
|||
*/
|
||||
already_AddRefed<nsIURI> GetNextSource();
|
||||
|
||||
/**
|
||||
* Changes mDelayingLoadEvent, and will call BlockOnLoad()/UnblockOnLoad()
|
||||
* on the owning document, so it can delay the load event firing.
|
||||
*/
|
||||
void ChangeDelayLoadStatus(PRBool aDelay);
|
||||
|
||||
nsRefPtr<nsMediaDecoder> mDecoder;
|
||||
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
|
@ -308,6 +314,10 @@ protected:
|
|||
// when selecting a resource to load.
|
||||
nsCOMPtr<nsIDOMRange> mSourcePointer;
|
||||
|
||||
// Points to the document whose load we're blocking. This is the document
|
||||
// we're bound to when loading starts.
|
||||
nsCOMPtr<nsIDocument> mLoadBlockedDoc;
|
||||
|
||||
// Media loading flags. See:
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#video)
|
||||
nsMediaNetworkState mNetworkState;
|
||||
|
@ -392,4 +402,12 @@ protected:
|
|||
|
||||
// PR_TRUE if we're loading exclusively from the src attribute's resource.
|
||||
PRPackedBool mIsLoadingFromSrcAttribute;
|
||||
|
||||
// PR_TRUE if we're delaying the "load" event. They are delayed until either
|
||||
// an error occurs, or the first frame is loaded.
|
||||
PRPackedBool mDelayingLoadEvent;
|
||||
|
||||
// PR_TRUE when we've got a task queued to call SelectResource(),
|
||||
// or while we're running SelectResource().
|
||||
PRPackedBool mIsRunningSelectResource;
|
||||
};
|
||||
|
|
|
@ -144,20 +144,30 @@ public:
|
|||
SelectResourceEvent(nsHTMLMediaElement *aElement)
|
||||
: nsMediaEvent(aElement) {}
|
||||
NS_IMETHOD Run() {
|
||||
if (!IsCancelled())
|
||||
if (!IsCancelled()) {
|
||||
NS_ASSERTION(mElement->mIsRunningSelectResource,
|
||||
"Should have flagged that we're running SelectResource()");
|
||||
mElement->SelectResource();
|
||||
mElement->mIsRunningSelectResource = PR_FALSE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
void nsHTMLMediaElement::QueueSelectResourceTask()
|
||||
{
|
||||
// Don't allow multiple async select resource calls to be queued.
|
||||
if (mIsRunningSelectResource)
|
||||
return;
|
||||
mIsRunningSelectResource = PR_TRUE;
|
||||
ChangeDelayLoadStatus(PR_TRUE);
|
||||
nsCOMPtr<nsIRunnable> event = new SelectResourceEvent(this);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::QueueLoadFromSourceTask()
|
||||
{
|
||||
ChangeDelayLoadStatus(PR_TRUE);
|
||||
nsCOMPtr<nsIRunnable> event = new LoadNextSourceEvent(this);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
@ -237,6 +247,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLMediaElement)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLMediaElement, nsGenericHTMLElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSourcePointer)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLoadBlockedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLMediaElement, nsGenericHTMLElement)
|
||||
|
@ -337,6 +348,8 @@ void nsHTMLMediaElement::AbortExistingLoads()
|
|||
// TODO: The current playback position must be set to 0.
|
||||
DispatchSimpleEvent(NS_LITERAL_STRING("emptied"));
|
||||
}
|
||||
|
||||
mIsRunningSelectResource = PR_FALSE;
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::NoSupportedMediaError()
|
||||
|
@ -344,6 +357,7 @@ void nsHTMLMediaElement::NoSupportedMediaError()
|
|||
mError = new nsHTMLMediaError(nsIDOMHTMLMediaError::MEDIA_ERR_NONE_SUPPORTED);
|
||||
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
|
||||
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
|
||||
ChangeDelayLoadStatus(PR_FALSE);
|
||||
}
|
||||
|
||||
/* void load (); */
|
||||
|
@ -390,6 +404,7 @@ void nsHTMLMediaElement::SelectResource()
|
|||
// element children, wait. (This steps might wait forever.)
|
||||
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
|
||||
mLoadWaitStatus = WAITING_FOR_SRC_OR_SOURCE;
|
||||
ChangeDelayLoadStatus(PR_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -426,6 +441,8 @@ void nsHTMLMediaElement::NotifyLoadError()
|
|||
|
||||
void nsHTMLMediaElement::LoadFromSourceChildren()
|
||||
{
|
||||
NS_ASSERTION(!IsInDoc() || mDelayingLoadEvent,
|
||||
"Should delay load event while loading in document");
|
||||
while (PR_TRUE) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri = GetNextSource();
|
||||
|
@ -450,6 +467,8 @@ void nsHTMLMediaElement::LoadFromSourceChildren()
|
|||
|
||||
nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI)
|
||||
{
|
||||
NS_ASSERTION(!IsInDoc() || mDelayingLoadEvent,
|
||||
"Should delay load event while loading in document");
|
||||
nsresult rv;
|
||||
|
||||
if (mChannel) {
|
||||
|
@ -540,6 +559,8 @@ nsresult nsHTMLMediaElement::LoadWithChannel(nsIChannel *aChannel,
|
|||
|
||||
AbortExistingLoads();
|
||||
|
||||
ChangeDelayLoadStatus(PR_TRUE);
|
||||
|
||||
nsresult rv = InitializeDecoderForChannel(aChannel, aListener);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -699,7 +720,9 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
|
|||
mIsBindingToTree(PR_FALSE),
|
||||
mLoadWaitStatus(NOT_WAITING),
|
||||
mIsLoadingFromSrcAttribute(PR_FALSE),
|
||||
mIsRunningLoadMethod(PR_FALSE)
|
||||
mIsRunningLoadMethod(PR_FALSE),
|
||||
mDelayingLoadEvent(PR_FALSE),
|
||||
mIsRunningSelectResource(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -831,7 +854,6 @@ void nsHTMLMediaElement::UnbindFromTree(PRBool aDeep,
|
|||
{
|
||||
if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY)
|
||||
Pause();
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
|
@ -1138,6 +1160,7 @@ void nsHTMLMediaElement::MetadataLoaded()
|
|||
void nsHTMLMediaElement::FirstFrameLoaded()
|
||||
{
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
|
||||
ChangeDelayLoadStatus(PR_FALSE);
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::ResourceLoaded()
|
||||
|
@ -1155,6 +1178,7 @@ void nsHTMLMediaElement::NetworkError()
|
|||
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
|
||||
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
|
||||
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied"));
|
||||
ChangeDelayLoadStatus(PR_FALSE);
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::PlaybackEnded()
|
||||
|
@ -1528,3 +1552,20 @@ already_AddRefed<nsIURI> nsHTMLMediaElement::GetNextSource()
|
|||
NS_NOTREACHED("Execution should not reach here!");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::ChangeDelayLoadStatus(PRBool aDelay) {
|
||||
if (mDelayingLoadEvent == aDelay)
|
||||
return;
|
||||
|
||||
LOG(PR_LOG_DEBUG, ("ChangeDelayLoadStatus(%d) doc=0x%p", aDelay, mLoadBlockedDoc.get()));
|
||||
mDelayingLoadEvent = aDelay;
|
||||
|
||||
if (aDelay) {
|
||||
mLoadBlockedDoc = GetOwnerDoc();
|
||||
mLoadBlockedDoc->BlockOnload();
|
||||
} else {
|
||||
NS_ASSERTION(mLoadBlockedDoc, "Need a doc to block on");
|
||||
mLoadBlockedDoc->UnblockOnload(PR_FALSE);
|
||||
mLoadBlockedDoc = nsnull;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ _TEST_FILES += \
|
|||
test_contentDuration4.html \
|
||||
test_contentDuration5.html \
|
||||
test_contentDuration6.html \
|
||||
test_delay_load.html \
|
||||
test_duration1.html \
|
||||
test_ended1.html \
|
||||
test_ended2.html \
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=479711
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 479711</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"/>
|
||||
<script>
|
||||
|
||||
var gLoadedDataCount = 0;
|
||||
|
||||
function log(msg) {
|
||||
//document.getElementById('log').innerHTML += "<p>"+msg+"</p>";
|
||||
//dump(msg + "\n");
|
||||
}
|
||||
|
||||
function loadeddata() {
|
||||
gLoadedDataCount++;
|
||||
}
|
||||
|
||||
function loaded() {
|
||||
is(gLoadedDataCount, 5, "onload was not delayed until after metadataloaded");
|
||||
log("doc-loaded gLoadedDataCount = " + gLoadedDataCount);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
addLoadEvent(loaded);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=479711">Mozilla Bug 479711</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<video src="320x240.ogv" onloadeddata="loadeddata();"></video>
|
||||
|
||||
|
||||
<div id="log" style="font-size: small;"></div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 479711 **/
|
||||
|
||||
var gEventTypes = [ 'loadstart', 'progress', 'suspend', 'load', 'abort', 'error', 'emptied', 'stalled', 'play', 'pause', 'loadedmetadata', 'loadeddata', 'waiting', 'playing', 'canplay', 'canplaythrough', 'seeking', 'seeked', 'timeupdate', 'ended', 'ratechange', 'durationchange', 'volumechange' ];
|
||||
|
||||
|
||||
|
||||
function listener(evt) {
|
||||
log('event ' + evt.target.id + " " + evt.type);
|
||||
}
|
||||
|
||||
function createVideo(id) {
|
||||
var v = document.createElement("video");
|
||||
v.id = id;
|
||||
for (var i=0; i<gEventTypes.length; i++) {
|
||||
var t = gEventTypes[i];
|
||||
v.addEventListener(t, listener, false);
|
||||
}
|
||||
v.addEventListener('loadeddata', loadeddata, false);
|
||||
v.src = "http://localhost:8888/tests/content/media/video/test/320x240.ogv";
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
// Load, add, then remove.
|
||||
var v1 = createVideo("v1");
|
||||
v1.load();
|
||||
document.body.appendChild(v1);
|
||||
v1.parentNode.removeChild(v1);
|
||||
|
||||
// Load and add.
|
||||
var v2 = createVideo("v2");
|
||||
v2.load();
|
||||
document.body.appendChild(v2);
|
||||
|
||||
// Load outside of doc.
|
||||
var v3 = createVideo("v3");
|
||||
v3.load();
|
||||
|
||||
// Load and move to another document.
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var v4 = createVideo("v4");
|
||||
v4.load(); // load started while in this document, this doc's load will block until
|
||||
// the video's finished loading (in the other document).
|
||||
var gTestWindow = window.open("", "testWindow", "width=400,height=400");
|
||||
gTestWindow.document.body.appendChild(v4);
|
||||
v4.addEventListener('load',
|
||||
function() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
gTestWindow.close();
|
||||
}, false);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv"
|
||||
style="width:140px; height:300px; position:relative; left:100px;"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
style="width:140px; height:300px; position:relative; left:100px;"></video>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv"
|
||||
style="width:680px; height:200px; position:relative; top:200px;"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
style="width:680px; height:200px; position:relative; top:200px;"></video>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv"
|
||||
style="width:280px; height:600px; position:relative; left:200px;"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
style="width:280px; height:600px; position:relative; left:200px;"></video>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
<video id="v" src="black140x100.ogv"></video>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv" style="width:0"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
<video id="v" src="black140x100.ogv" style="width:0"></video>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv" style="height:0"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
<video id="v" src="black140x100.ogv" style="height:0"></video>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait" reftest-zoom="1.5">
|
||||
<html reftest-zoom="1.5">
|
||||
<body style="background:white; margin:0">
|
||||
<video id="v" src="black140x100.ogv"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
<video id="v" src="black140x100.ogv"></video>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Загрузка…
Ссылка в новой задаче