LibWeb/HTML: Use DOM's post-connection steps for iframe elements

See: https://github.com/whatwg/html/commit/c8ec987d1
This commit is contained in:
Shannon Booth 2024-12-15 02:59:23 +13:00 committed by Tim Flynn
parent 0a90143420
commit 18dddaa742
Notes: github-actions[bot] 2024-12-14 20:07:33 +00:00
4 changed files with 105 additions and 13 deletions

View file

@ -62,28 +62,22 @@ void HTMLIFrameElement::attribute_changed(FlyString const& name, Optional<String
}
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:the-iframe-element-6
void HTMLIFrameElement::inserted()
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:html-element-post-connection-steps
void HTMLIFrameElement::post_connection()
{
HTMLElement::inserted();
// The iframe HTML element insertion steps, given insertedNode, are:
// 1. If insertedNode's shadow-including root's browsing context is null, then return.
if (!is<DOM::Document>(shadow_including_root()))
return;
DOM::Document& document = verify_cast<DOM::Document>(shadow_including_root());
// NOTE: The check for "not fully active" is to prevent a crash on the dom/nodes/node-appendchild-crash.html WPT test.
if (!document.browsing_context() || !document.is_fully_active())
return;
// 2. Create a new child navigable for insertedNode.
// The iframe HTML element post-connection steps, given insertedNode, are:
// 1. Create a new child navigable for insertedNode.
MUST(create_new_child_navigable(GC::create_function(realm().heap(), [this] {
// FIXME: 3. If insertedNode has a sandbox attribute, then parse the sandboxing directive given the attribute's
// FIXME: 2. If insertedNode has a sandbox attribute, then parse the sandboxing directive given the attribute's
// value and insertedNode's iframe sandboxing flag set.
// 4. Process the iframe attributes for insertedNode, with initialInsertion set to true.
// 3. Process the iframe attributes for insertedNode, with initialInsertion set to true.
process_the_iframe_attributes(true);
set_content_navigable_initialized();
})));

View file

@ -41,7 +41,7 @@ private:
virtual void initialize(JS::Realm&) override;
// ^DOM::Element
virtual void inserted() override;
virtual void post_connection() override;
virtual void removed_from(Node*) override;
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
virtual i32 default_tab_index_value() const override;

View file

@ -0,0 +1,9 @@
Harness status: OK
Found 4 tests
4 Pass
Pass Script inserted after an iframe in the same appendChild() call can observe the iframe's non-null contentWindow
Pass A script inserted atomically before an iframe (using a div) does not observe the iframe's contentWindow, since the 'script running' and 'iframe setup' both happen in order, after DOM insertion completes
Pass A script inserted atomically before an iframe (using a DocumentFragment) does not observe the iframe's contentWindow, since the 'script running' and 'iframe setup' both happen in order, after DOM insertion completes
Pass A script inserted atomically before an iframe (using a append() with multiple arguments) does not observe the iframe's contentWindow, since the 'script running' and 'iframe setup' both happen in order, after DOM insertion completes

View file

@ -0,0 +1,89 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Node.appendChild: inserting script and iframe</title>
<script src=../../../resources/testharness.js></script>
<script src=../../../resources/testharnessreport.js></script>
<body>
<script>
const kScriptContent = `
state = iframe.contentWindow ? "iframe with content window" : "contentWindow is null";
`;
// This test ensures that a later-inserted script can observe an
// earlier-inserted iframe's contentWindow.
test(t => {
window.state = "script not run yet";
window.iframe = document.createElement("iframe");
t.add_cleanup(() => window.iframe.remove());
const script = document.createElement("script");
script.textContent = kScriptContent;
const div = document.createElement("div");
div.appendChild(iframe);
div.appendChild(script);
assert_equals(state, "script not run yet");
document.body.appendChild(div);
assert_equals(state, "iframe with content window");
}, "Script inserted after an iframe in the same appendChild() call can " +
"observe the iframe's non-null contentWindow");
// The below tests assert that an earlier-inserted script does not observe a
// later-inserted iframe's contentWindow.
test(t => {
window.state = "script not run yet";
window.iframe = document.createElement("iframe");
t.add_cleanup(() => window.iframe.remove());
const script = document.createElement("script");
script.textContent = kScriptContent;
const div = document.createElement("div");
div.appendChild(script);
div.appendChild(iframe);
assert_equals(state, "script not run yet");
document.body.appendChild(div);
assert_equals(state, "contentWindow is null");
}, "A script inserted atomically before an iframe (using a div) does not " +
"observe the iframe's contentWindow, since the 'script running' and " +
"'iframe setup' both happen in order, after DOM insertion completes");
test(t => {
window.state = "script not run yet";
window.iframe = document.createElement("iframe");
t.add_cleanup(() => window.iframe.remove());
const script = document.createElement("script");
script.textContent = kScriptContent;
const df = document.createDocumentFragment();
df.appendChild(script);
df.appendChild(iframe);
assert_equals(state, "script not run yet");
document.body.appendChild(df);
assert_equals(state, "contentWindow is null");
}, "A script inserted atomically before an iframe (using a DocumentFragment) " +
"does not observe the iframe's contentWindow, since the 'script running' " +
"and 'iframe setup' both happen in order, after DOM insertion completes");
test(t => {
window.state = "script not run yet";
window.iframe = document.createElement("iframe");
t.add_cleanup(() => window.iframe.remove());
const script = document.createElement("script");
script.textContent = kScriptContent;
assert_equals(state, "script not run yet");
document.body.append(script, iframe);
assert_equals(state, "contentWindow is null");
}, "A script inserted atomically before an iframe (using a append() with " +
"multiple arguments) does not observe the iframe's contentWindow, since " +
"the 'script running' and 'iframe setup' both happen in order, after DOM " +
"insertion completes");
</script>