Browse Source

LibWeb: Implement window.stop()

Fixes a handful of timeouts on WPT.
Andreas Kling 7 months ago
parent
commit
3f461b96df

+ 14 - 0
Libraries/LibWeb/HTML/Navigable.cpp

@@ -2234,4 +2234,18 @@ void Navigable::unregister_navigation_observer(Badge<NavigationObserver>, Naviga
     VERIFY(was_removed);
 }
 
+// https://html.spec.whatwg.org/multipage/document-lifecycle.html#nav-stop
+void Navigable::stop_loading()
+{
+    // 1. Let document be navigable's active document.
+    auto document = active_document();
+
+    // 2. If document's unload counter is 0, and navigable's ongoing navigation is a navigation ID, then set the ongoing navigation for navigable to null.
+    if (document->unload_counter() == 0 && ongoing_navigation().has<String>())
+        set_ongoing_navigation(Empty {});
+
+    // 3. Abort a document and its descendants given document.
+    document->abort_a_document_and_its_descendants();
+}
+
 }

+ 2 - 0
Libraries/LibWeb/HTML/Navigable.h

@@ -74,6 +74,8 @@ public:
     void set_closing(bool value) { m_closing = value; }
     bool is_script_closable();
 
+    void stop_loading();
+
     void set_delaying_load_events(bool value);
     bool is_delaying_load_events() const { return m_delaying_the_load_event.has_value(); }
 

+ 12 - 0
Libraries/LibWeb/HTML/Window.cpp

@@ -856,6 +856,18 @@ GC::Ref<History> Window::history() const
     return associated_document().history();
 }
 
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-stop
+void Window::stop()
+{
+    // 1. If this's navigable is null, then return.
+    auto navigable = this->navigable();
+    if (!navigable)
+        return;
+
+    // 2. Stop loading this's navigable.
+    navigable->stop_loading();
+}
+
 // https://html.spec.whatwg.org/multipage/interaction.html#dom-window-focus
 void Window::focus()
 {

+ 1 - 0
Libraries/LibWeb/HTML/Window.h

@@ -154,6 +154,7 @@ public:
     [[nodiscard]] GC::Ref<Location> location();
     GC::Ref<History> history() const;
     GC::Ref<Navigation> navigation();
+    void stop();
     void focus();
     void blur();
 

+ 1 - 0
Libraries/LibWeb/HTML/Window.idl

@@ -30,6 +30,7 @@ interface Window : EventTarget {
     readonly attribute History history;
     readonly attribute Navigation navigation;
     readonly attribute CustomElementRegistry customElements;
+    undefined stop();
     undefined focus();
     undefined blur();
 

+ 2 - 0
Tests/LibWeb/TestConfig.ini

@@ -47,6 +47,8 @@ Text/input/wpt-import/html/syntax/parsing/support/no-doctype-name-line.html
 Text/input/wpt-import/html/syntax/parsing/support/no-doctype-name-space.html
 Text/input/wpt-import/html/semantics/embedded-content/the-iframe-element/support/sandbox_allow_script.html
 Text/input/wpt-import/html/semantics/embedded-content/the-iframe-element/support/blank.htm
+Text/input/wpt-import/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html
+Text/input/wpt-import/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html
 
 ; Unknown, imported as skipped in #2148
 Text/input/wpt-import/html/infrastructure/safe-passing-of-structured-data/structuredclone_0.html

+ 7 - 0
Tests/LibWeb/Text/expected/wpt-import/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.txt

@@ -0,0 +1,7 @@
+Harness status: OK
+
+Found 2 tests
+
+2 Pass
+Pass	document.open() after parser is aborted
+Pass	async document.open() after parser is aborted

+ 8 - 0
Tests/LibWeb/Text/input/wpt-import/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.html

@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<script src="../../../../resources/testharness.js"></script>
+<script src="../../../../resources/testharnessreport.js"></script>
+
+<div id=log></div>
+<script src="../../../../html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js"></script>

+ 31 - 0
Tests/LibWeb/Text/input/wpt-import/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js

@@ -0,0 +1,31 @@
+// document.open() bails out early if there is an active parser with non-zero
+// script nesting level or if a load was aborted while there was an active
+// parser. window.stop() aborts the current parser, so once it has been called
+// while a parser is active, document.open() will no longer do anything to that
+// document,
+
+window.handlers = {};
+
+async_test(t => {
+  const frame = document.body.appendChild(document.createElement("iframe"));
+  t.add_cleanup(() => frame.remove());
+  frame.src = "resources/aborted-parser-frame.html";
+  window.handlers.afterOpen = t.step_func_done(() => {
+    const openCalled = frame.contentDocument.childNodes.length === 0;
+    assert_false(openCalled, "child document should not be empty");
+    assert_equals(frame.contentDocument.querySelector("p").textContent,
+                  "Text", "Should still have our paragraph");
+  });
+}, "document.open() after parser is aborted");
+
+async_test(t => {
+  const frame = document.body.appendChild(document.createElement("iframe"));
+  t.add_cleanup(() => frame.remove());
+  frame.src = "resources/aborted-parser-async-frame.html";
+  window.handlers.afterOpenAsync = t.step_func_done(() => {
+    const openCalled = frame.contentDocument.childNodes.length === 0;
+    assert_false(openCalled, "child document should not be empty");
+    assert_equals(frame.contentDocument.querySelector("p").textContent,
+                  "Text", "Should still have our paragraph");
+  });
+}, "async document.open() after parser is aborted");

+ 9 - 0
Tests/LibWeb/Text/input/wpt-import/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html

@@ -0,0 +1,9 @@
+<!doctype html>
+<p>Text</p>
+<script>
+window.stop();
+parent.step_timeout(() => {
+  document.open();
+  parent.handlers.afterOpenAsync();
+}, 10);
+</script>

+ 7 - 0
Tests/LibWeb/Text/input/wpt-import/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html

@@ -0,0 +1,7 @@
+<!doctype html>
+<p>Text</p>
+<script>
+window.stop();
+document.open();
+parent.handlers.afterOpen();
+</script>