Bug 2062317, be more synchronous with DOMContentLoaded, r=farre
Differential Revision: https://phabricator.services.mozilla.com/D321732
This commit is contained in:
committed by
opettay@mozilla.com
parent
c70773c334
commit
91972506c1
@@ -10342,7 +10342,7 @@ nsresult nsDocShell::CompleteInitialAboutBlankLoad(
|
||||
|
||||
// Mechanisms in Document will force a load from EndLoad()
|
||||
// even if there are still blockers.
|
||||
doc->EndLoad();
|
||||
doc->EndLoad(/* aFireDOMContentLoadedSync = */ true);
|
||||
// Can't assert any postcondition, because the load event
|
||||
// handler may have started loading something new in this
|
||||
// docshell.
|
||||
|
||||
+39
-14
@@ -8770,7 +8770,7 @@ void Document::MozSetImageElement(const nsAString& aImageElementId,
|
||||
}
|
||||
}
|
||||
|
||||
void Document::DispatchContentLoadedEvents() {
|
||||
void Document::DispatchContentLoadedEvents(bool aFinishSync) {
|
||||
// If you add early returns from this method, make sure you're
|
||||
// calling UnblockOnload properly.
|
||||
|
||||
@@ -8882,6 +8882,19 @@ void Document::DispatchContentLoadedEvents() {
|
||||
}
|
||||
}
|
||||
|
||||
if (aFinishSync) {
|
||||
FinishDOMContentLoaded();
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep the load event on a task, so that its timing does not change.
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
NewRunnableMethod("Document::FinishDOMContentLoaded", this,
|
||||
&Document::FinishDOMContentLoaded);
|
||||
Dispatch(ev.forget());
|
||||
}
|
||||
|
||||
void Document::FinishDOMContentLoaded() {
|
||||
if (mSetCompleteAfterDOMContentLoaded) {
|
||||
SetReadyStateInternal(ReadyState::READYSTATE_COMPLETE);
|
||||
mSetCompleteAfterDOMContentLoaded = false;
|
||||
@@ -8890,7 +8903,7 @@ void Document::DispatchContentLoadedEvents() {
|
||||
UnblockOnload(true);
|
||||
}
|
||||
|
||||
void Document::EndLoad() {
|
||||
void Document::EndLoad(bool aFireDOMContentLoadedSync) {
|
||||
bool turnOnEditing =
|
||||
mParser && (IsInDesignMode() || mContentEditableCount > 0);
|
||||
|
||||
@@ -8938,7 +8951,7 @@ void Document::EndLoad() {
|
||||
}
|
||||
mDidCallBeginLoad = false;
|
||||
|
||||
UnblockDOMContentLoaded();
|
||||
UnblockDOMContentLoaded(aFireDOMContentLoadedSync);
|
||||
|
||||
if (turnOnEditing) {
|
||||
EditingStateChanged();
|
||||
@@ -8963,7 +8976,7 @@ void Document::EndLoad() {
|
||||
}
|
||||
}
|
||||
|
||||
void Document::UnblockDOMContentLoaded() {
|
||||
void Document::UnblockDOMContentLoaded(bool aFireSync) {
|
||||
MOZ_ASSERT(mBlockDOMContentLoaded);
|
||||
if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) {
|
||||
return;
|
||||
@@ -8974,17 +8987,28 @@ void Document::UnblockDOMContentLoaded() {
|
||||
|
||||
mDidFireDOMContentLoaded = true;
|
||||
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(IsInitialDocument() || mReadyState == READYSTATE_INTERACTIVE);
|
||||
if (!mSynchronousDOMContentLoaded) {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!IsInitialDocument());
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
NewRunnableMethod("Document::DispatchContentLoadedEvents", this,
|
||||
&Document::DispatchContentLoadedEvents);
|
||||
Dispatch(ev.forget());
|
||||
} else {
|
||||
DispatchContentLoadedEvents();
|
||||
|
||||
// These documents need the load event unblocked before we return.
|
||||
if (mSynchronousDOMContentLoaded) {
|
||||
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
|
||||
DispatchContentLoadedEvents(/* aFinishSync = */ true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aFireSync &&
|
||||
StaticPrefs::dom_document_domcontentloaded_synchronous_enabled()) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
NewRunnableMethod<bool>("Document::DispatchContentLoadedEvents", this,
|
||||
&Document::DispatchContentLoadedEvents, false));
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!IsInitialDocument());
|
||||
Dispatch(NewRunnableMethod<bool>("Document::DispatchContentLoadedEvents",
|
||||
this, &Document::DispatchContentLoadedEvents,
|
||||
true));
|
||||
}
|
||||
|
||||
void Document::ElementStateChanged(Element* aElement, ElementState aStateMask) {
|
||||
@@ -15326,7 +15350,8 @@ class UnblockParsingPromiseHandler final : public PromiseNativeHandler {
|
||||
// parser state for this document. Maybe someone caused it to stop being
|
||||
// parsed, so CreatorParserOrNull() is returning null, but we still want
|
||||
// to unblock these.
|
||||
mDocument->UnblockDOMContentLoaded();
|
||||
// Async, because this also runs from our destructor.
|
||||
mDocument->UnblockDOMContentLoaded(/* aFireSync = */ false);
|
||||
mDocument->UnblockOnload(false);
|
||||
}
|
||||
mParser = nullptr;
|
||||
|
||||
+9
-3
@@ -1670,7 +1670,9 @@ class Document : public nsINode,
|
||||
NotNull<const Encoding*>& aEncoding,
|
||||
nsHtml5TreeOpExecutor* aExecutor);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void DispatchContentLoadedEvents();
|
||||
MOZ_CAN_RUN_SCRIPT void DispatchContentLoadedEvents(bool aFinishSync);
|
||||
// Unblocks the load event. An aborted load also gets readyState complete.
|
||||
MOZ_CAN_RUN_SCRIPT void FinishDOMContentLoaded();
|
||||
|
||||
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY void DispatchPageTransition(
|
||||
@@ -2240,7 +2242,10 @@ class Document : public nsINode,
|
||||
uint32_t UpdateNestingLevel() { return mUpdateNestLevel; }
|
||||
|
||||
void BeginLoad();
|
||||
virtual void EndLoad();
|
||||
// aFireDOMContentLoadedSync must be false for a terminated parse.
|
||||
// See bug 344305.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void EndLoad(
|
||||
bool aFireDOMContentLoadedSync);
|
||||
|
||||
enum ReadyState {
|
||||
READYSTATE_UNINITIALIZED = 0,
|
||||
@@ -2643,7 +2648,8 @@ class Document : public nsINode,
|
||||
|
||||
void BlockDOMContentLoaded() { ++mBlockDOMContentLoaded; }
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY void UnblockDOMContentLoaded();
|
||||
// aFireSync false fires DOMContentLoaded from a task. See bug 344305.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY void UnblockDOMContentLoaded(bool aFireSync);
|
||||
|
||||
/**
|
||||
* Notification that the page has been shown, for documents which are loaded
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// document.open() clears the content while DOMContentLoaded is being fired.
|
||||
document.open();
|
||||
document.write(
|
||||
"<!DOCTYPE html><html><body><script>" +
|
||||
"parent.postMessage('reopened', '*');" +
|
||||
"<\/script></body></html>");
|
||||
document.close();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded",
|
||||
() => parent.postMessage("DOMContentLoaded", "*"));
|
||||
// Terminate the parse, see bug 344305.
|
||||
window.stop();
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
@@ -12,6 +12,8 @@ support-files = [
|
||||
"iframe_main_bug1022229.html",
|
||||
"iframe_sandbox_bug1022229.html",
|
||||
"file_empty.html",
|
||||
"file_domcontentloaded_document_open.html",
|
||||
"file_domcontentloaded_terminated_parse.html",
|
||||
"iframe_postMessage_solidus.html",
|
||||
"file_setname.html",
|
||||
"345339_iframe.html",
|
||||
@@ -352,6 +354,10 @@ skip-if = [
|
||||
"http3",
|
||||
]
|
||||
|
||||
["test_domcontentloaded_document_open.html"]
|
||||
|
||||
["test_domcontentloaded_terminated_parse.html"]
|
||||
|
||||
["test_domparser_null_char.html"]
|
||||
|
||||
["test_domparsing.html"]
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test document.open() from a DOMContentLoaded listener</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="f"></iframe>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("message", event => {
|
||||
is(event.data, "reopened",
|
||||
"the content written from a DOMContentLoaded listener was parsed");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
document.getElementById("f").src = "file_domcontentloaded_document_open.html";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test DOMContentLoaded after a terminated parse</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="f"></iframe>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("message", event => {
|
||||
is(event.data, "DOMContentLoaded",
|
||||
"DOMContentLoaded fires after the parse was terminated");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
document.getElementById("f").src = "file_domcontentloaded_terminated_parse.html";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -24,6 +24,7 @@ const server = XPCShellContentUtils.createHttpServer({
|
||||
|
||||
// XML document with only a <script> tag as the document element.
|
||||
const PAGE_URL = "http://example.com/";
|
||||
const DCL_PAGE_URL = "http://example.com/blockdcl";
|
||||
server.registerPathHandler("/", (request, response) => {
|
||||
response.setHeader("Content-Type", "application/xhtml+xml");
|
||||
response.write(String.raw`<!DOCTYPE html>
|
||||
@@ -31,6 +32,11 @@ server.registerPathHandler("/", (request, response) => {
|
||||
`);
|
||||
});
|
||||
|
||||
server.registerPathHandler("/blockdcl", (request, response) => {
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.write("<!DOCTYPE html><html><body>blockdcl</body></html>");
|
||||
});
|
||||
|
||||
let resolveResumeScriptPromise;
|
||||
let resumeScriptPromise = new Promise(resolve => {
|
||||
resolveResumeScriptPromise = resolve;
|
||||
@@ -119,3 +125,57 @@ add_task(async function test_nested_blockParser() {
|
||||
let page = await pagePromise;
|
||||
await page.close();
|
||||
});
|
||||
|
||||
// Tests that blockParsing() also blocks DOMContentLoaded, and that
|
||||
// DOMContentLoaded is fired once the blocker promise settles.
|
||||
add_task(async function test_blockParsing_blocksDOMContentLoaded() {
|
||||
let resolveBlockerPromise;
|
||||
let dclFired = false;
|
||||
let dclPromise;
|
||||
|
||||
let docElementPromise = TestUtils.topicObserved(
|
||||
"document-element-inserted",
|
||||
doc => {
|
||||
if (doc.location.href !== DCL_PAGE_URL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let blockerPromise = new Promise(resolve => {
|
||||
resolveBlockerPromise = resolve;
|
||||
});
|
||||
doc.blockParsing(blockerPromise);
|
||||
|
||||
dclPromise = new Promise(resolve => {
|
||||
doc.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
() => {
|
||||
dclFired = true;
|
||||
resolve();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
let pagePromise = XPCShellContentUtils.loadContentPage(DCL_PAGE_URL, {
|
||||
remote: false,
|
||||
});
|
||||
|
||||
await docElementPromise;
|
||||
|
||||
// Make some trips through the event loop to be safe.
|
||||
await delay();
|
||||
await delay();
|
||||
|
||||
Assert.ok(!dclFired, "DOMContentLoaded is blocked while parsing is blocked");
|
||||
|
||||
resolveBlockerPromise();
|
||||
await dclPromise;
|
||||
|
||||
Assert.ok(dclFired, "DOMContentLoaded is fired once the blocker settles");
|
||||
|
||||
let page = await pagePromise;
|
||||
await page.close();
|
||||
});
|
||||
|
||||
@@ -694,7 +694,7 @@ nsresult PrototypeDocumentContentSink::DoneWalking() {
|
||||
|
||||
doc->SetScrollToRef(mDocument->GetDocumentURI());
|
||||
|
||||
doc->EndLoad();
|
||||
doc->EndLoad(/* aFireDOMContentLoadedSync = */ true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -4638,9 +4638,11 @@ void ScriptLoader::ProcessPendingRequests(bool aAllowBypassingParserBlocking) {
|
||||
|
||||
if (mDeferCheckpointReached && mDocument && !mParserBlockingRequest &&
|
||||
mNonAsyncExternalScriptInsertedRequests.isEmpty() &&
|
||||
mXSLTRequests.isEmpty() && mDeferRequests.isEmpty() &&
|
||||
MaybeRemovedDeferRequests()) {
|
||||
return ProcessPendingRequests();
|
||||
mXSLTRequests.isEmpty() && mDeferRequests.isEmpty()) {
|
||||
const RefPtr<ScriptLoader> self = this;
|
||||
if (self->MaybeRemovedDeferRequests()) {
|
||||
return self->ProcessPendingRequests();
|
||||
}
|
||||
}
|
||||
|
||||
if (mDeferCheckpointReached && mDocument && !mParserBlockingRequest &&
|
||||
@@ -5669,7 +5671,7 @@ void ScriptLoader::MaybeMoveToLoadedList(ScriptLoadRequest* aRequest) {
|
||||
bool ScriptLoader::MaybeRemovedDeferRequests() {
|
||||
if (mDeferRequests.isEmpty() && mDocument && mBlockingDOMContentLoaded) {
|
||||
mBlockingDOMContentLoaded = false;
|
||||
mDocument->UnblockDOMContentLoaded();
|
||||
mDocument->UnblockDOMContentLoaded(/* aFireSync = */ true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -862,7 +862,7 @@ class ScriptLoader final : public JS::loader::ScriptLoaderInterface {
|
||||
|
||||
void AddDeferRequest(ScriptLoadRequest* aRequest);
|
||||
void AddAsyncRequest(ScriptLoadRequest* aRequest);
|
||||
bool MaybeRemovedDeferRequests();
|
||||
MOZ_CAN_RUN_SCRIPT bool MaybeRemovedDeferRequests();
|
||||
|
||||
bool ShouldApplyDelazifyStrategy(ScriptLoadRequest* aRequest);
|
||||
void ApplyDelazifyStrategy(JS::CompileOptions* aOptions);
|
||||
|
||||
@@ -298,11 +298,11 @@ nsresult XMLDocument::StartDocumentLoad(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void XMLDocument::EndLoad() {
|
||||
void XMLDocument::EndLoad(bool aFireDOMContentLoadedSync) {
|
||||
mChannelIsPending = false;
|
||||
|
||||
mSynchronousDOMContentLoaded = mLoadedAsData;
|
||||
Document::EndLoad();
|
||||
Document::EndLoad(aFireDOMContentLoadedSync);
|
||||
if (mSynchronousDOMContentLoaded) {
|
||||
mSynchronousDOMContentLoaded = false;
|
||||
Document::SetReadyStateInternal(Document::READYSTATE_COMPLETE);
|
||||
|
||||
@@ -40,7 +40,8 @@ class XMLDocument : public Document {
|
||||
bool aReset = true) override;
|
||||
|
||||
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void EndLoad() override;
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void EndLoad(
|
||||
bool aFireDOMContentLoadedSync) override;
|
||||
|
||||
virtual nsresult Init(nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aPartitionedPrincipal) override;
|
||||
|
||||
@@ -305,6 +305,7 @@ nsXMLContentSink::DidBuildModel(bool aTerminated) {
|
||||
mDocument->RemoveObserver(this);
|
||||
mIsDocumentObserver = false;
|
||||
|
||||
const RefPtr<nsXMLContentSink> kungFuDeathGrip(this);
|
||||
RefPtr<Document> doc = mDocument;
|
||||
if (!mDeferredLayoutStart && doc->IsBeingUsedAsImage()) {
|
||||
// Eagerly layout image documents, so that layout-triggered loads have a
|
||||
@@ -312,7 +313,7 @@ nsXMLContentSink::DidBuildModel(bool aTerminated) {
|
||||
doc->FlushPendingNotifications(FlushType::Layout);
|
||||
}
|
||||
|
||||
doc->EndLoad();
|
||||
doc->EndLoad(/* aFireDOMContentLoadedSync = */ !aTerminated);
|
||||
|
||||
DropParserAndPerfHint();
|
||||
}
|
||||
@@ -402,7 +403,7 @@ nsresult nsXMLContentSink::OnTransformDone(Document* aSourceDocument,
|
||||
ScrollToRef();
|
||||
}
|
||||
|
||||
originalDocument->EndLoad();
|
||||
originalDocument->EndLoad(/* aFireDOMContentLoadedSync = */ true);
|
||||
if (blockingOnload) {
|
||||
// This UnblockOnload call corresponds to the BlockOnload call in
|
||||
// nsContentSink::WillBuildModelImpl.
|
||||
|
||||
@@ -2817,6 +2817,12 @@
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Fire DOMContentLoaded at the end of parsing, instead of from a task.
|
||||
- name: dom.document.domcontentloaded.synchronous.enabled
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Enable/disable Gecko specific edit commands
|
||||
- name: dom.document.edit_command.contentReadOnly.enabled
|
||||
type: bool
|
||||
|
||||
@@ -258,7 +258,8 @@ nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated) {
|
||||
// This comes from nsXMLContentSink and the old (now removed)
|
||||
// nsHTMLContentSink. If this parser has been marked as broken, treat the end
|
||||
// of parse as forced termination.
|
||||
DidBuildModelImpl(aTerminated || NS_FAILED(IsBroken()));
|
||||
const bool terminated = aTerminated || NS_FAILED(IsBroken());
|
||||
DidBuildModelImpl(terminated);
|
||||
|
||||
bool destroying = true;
|
||||
if (mDocShell) {
|
||||
@@ -290,8 +291,11 @@ nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated) {
|
||||
|
||||
// We may not have called BeginLoad() if loading is terminated before
|
||||
// OnStartRequest call.
|
||||
// EndLoad below can run script which drops the parser.
|
||||
const RefPtr<nsHtml5Parser> parser = GetParser();
|
||||
|
||||
if (mStarted) {
|
||||
mDocument->EndLoad();
|
||||
mDocument->EndLoad(/* aFireDOMContentLoadedSync = */ !terminated);
|
||||
|
||||
// Log outcome only for top-level content navigations in order to
|
||||
// avoid noise from ad iframes.
|
||||
@@ -311,7 +315,7 @@ nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated) {
|
||||
// error pages.
|
||||
bool httpOk = false;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv = GetParser()->GetChannel(getter_AddRefs(channel));
|
||||
nsresult rv = parser->GetChannel(getter_AddRefs(channel));
|
||||
if (NS_SUCCEEDED(rv) && channel) {
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||
if (httpChannel) {
|
||||
@@ -422,7 +426,7 @@ nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated) {
|
||||
// before this executor's nsHtml5Parser has been made unreachable from its
|
||||
// nsHTMLDocument. (mDocument->EndLoad() above drops the parser from the
|
||||
// document.)
|
||||
GetParser()->DropStreamParser();
|
||||
parser->DropStreamParser();
|
||||
DropParserAndPerfHint();
|
||||
#ifdef GATHER_DOCWRITE_STATISTICS
|
||||
printf("UNSAFE SCRIPTS: %d\n", sUnsafeDocWrites);
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
[DOMContentLoaded-defer-task-order.tentative.html]
|
||||
prefs: [dom.document.domcontentloaded.synchronous.enabled:true]
|
||||
@@ -1,3 +1,6 @@
|
||||
[DOMContentLoaded-defer.html]
|
||||
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1242128
|
||||
|
||||
prefs: [dom.document.domcontentloaded.synchronous.enabled:true]
|
||||
# This test asserts an order which is not specified, see
|
||||
# https://github.com/web-platform-tests/wpt/issues/4267
|
||||
[The end: DOMContentLoaded and defer scripts]
|
||||
expected: FAIL
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>The end: DOMContentLoaded and a task queued from a defer script</title>
|
||||
<link rel=help href="https://html.spec.whatwg.org/multipage/#the-end">
|
||||
<link rel=help href="https://github.com/web-platform-tests/wpt/issues/4267">
|
||||
<!--
|
||||
Tentative: the order between DOMContentLoaded, which the specification queues
|
||||
on the DOM manipulation task source, and a timer task is not specified.
|
||||
DOMContentLoaded-defer.html asserts the opposite order.
|
||||
-->
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
var order = [];
|
||||
document.addEventListener("DOMContentLoaded", () => order.push("DOMContentLoaded"));
|
||||
|
||||
var t = async_test(
|
||||
"DOMContentLoaded fires before a task queued from a defer script");
|
||||
|
||||
function check() {
|
||||
t.step(() => {
|
||||
assert_array_equals(order, ["defer", "DOMContentLoaded", "timeout"]);
|
||||
});
|
||||
t.done();
|
||||
}
|
||||
</script>
|
||||
<script defer src="data:text/javascript,order.push('defer');t.step_timeout(()=>{order.push('timeout');check()},0)"></script>
|
||||
@@ -4,19 +4,17 @@
|
||||
<link rel="author" title="Divyansh Mangal" href="mailto:dmangal@microsoft.com">
|
||||
<link rel="help" href="https://w3c.github.io/svgwg/svg2-draft/linking.html#InterfaceSVGAElement">
|
||||
<title> Rel attribute with noreferrer value </title>
|
||||
<svg>
|
||||
<a id="test" href="resources/a.rel-noreferrer-policy-target.html" rel="noreferrer"></a>
|
||||
<script>
|
||||
var anchorElement = document.getElementById('test');
|
||||
<body>
|
||||
<script>
|
||||
// The link is in an iframe, because a test must not navigate its own top level
|
||||
// browsing context.
|
||||
async_test(t => {
|
||||
window.addEventListener("message", t.step_func_done(event => {
|
||||
assert_equals(event.data, "");
|
||||
}));
|
||||
|
||||
// Simulate a click event
|
||||
var event = new MouseEvent('click', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
|
||||
// Dispatch the event to the anchor element
|
||||
anchorElement.dispatchEvent(event);
|
||||
</script>
|
||||
</svg>
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "resources/a.rel-noreferrer-policy-frame.html";
|
||||
document.body.appendChild(iframe);
|
||||
}, "No Referrer policy attribute on svg anchor element is applied");
|
||||
</script>
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<svg>
|
||||
<a id="test" href="a.rel-noreferrer-policy-target.html" rel="noreferrer"></a>
|
||||
<script>
|
||||
document.getElementById("test").dispatchEvent(new MouseEvent("click", {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
}));
|
||||
</script>
|
||||
</svg>
|
||||
+1
-6
@@ -1,10 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<link rel="author" title="Divyansh Mangal" href="mailto:dmangal@microsoft.com">
|
||||
<link rel="help" href="https://w3c.github.io/svgwg/svg2-draft/linking.html#InterfaceSVGAElement">
|
||||
<script>
|
||||
test(function () {
|
||||
assert_equals("", document.referrer);
|
||||
}, "No Referrer policy attribute on svg anchor element is applied");
|
||||
parent.postMessage(document.referrer, "*");
|
||||
</script>
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
}
|
||||
|
||||
async function runTests() {
|
||||
// The drag needs a focused window.
|
||||
await SimpleTest.promiseFocus();
|
||||
await SpecialPowers.contentTransformsReceived(window);
|
||||
for (let currentTest of tests) {
|
||||
await test(currentTest.actual, currentTest.expected);
|
||||
|
||||
Reference in New Issue
Block a user