Sfoglia il codice sorgente

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

See: https://github.com/whatwg/html/commit/c8ec987d1
Shannon Booth 7 mesi fa
parent
commit
18dddaa742

+ 6 - 12
Libraries/LibWeb/HTML/HTMLIFrameElement.cpp

@@ -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());
     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.
     // 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())
     if (!document.browsing_context() || !document.is_fully_active())
         return;
         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] {
     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.
         //           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);
         process_the_iframe_attributes(true);
         set_content_navigable_initialized();
         set_content_navigable_initialized();
     })));
     })));

+ 1 - 1
Libraries/LibWeb/HTML/HTMLIFrameElement.h

@@ -41,7 +41,7 @@ private:
     virtual void initialize(JS::Realm&) override;
     virtual void initialize(JS::Realm&) override;
 
 
     // ^DOM::Element
     // ^DOM::Element
-    virtual void inserted() override;
+    virtual void post_connection() override;
     virtual void removed_from(Node*) 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 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;
     virtual i32 default_tab_index_value() const override;

+ 9 - 0
Tests/LibWeb/Text/expected/wpt-import/dom/nodes/insertion-removing-steps/Node-appendChild-script-and-iframe.tentative.txt

@@ -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

+ 89 - 0
Tests/LibWeb/Text/input/wpt-import/dom/nodes/insertion-removing-steps/Node-appendChild-script-and-iframe.tentative.html

@@ -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>