ソースを参照

LibWeb: Create a new WebView for window.open()'d top level traversables

Andrew Kaster 1 年間 前
コミット
adb5c27331

+ 16 - 4
Userland/Libraries/LibWeb/HTML/Navigable.cpp

@@ -412,17 +412,29 @@ Navigable::ChosenNavigable Navigable::choose_a_navigable(StringView name, Tokeni
             if (!Infra::is_ascii_case_insensitive_match(name, "_blank"sv))
                 target_name = MUST(String::from_utf8(name));
 
+            auto create_new_traversable_closure = [this, window_type, no_opener, target_name](JS::GCPtr<BrowsingContext> opener) -> JS::NonnullGCPtr<Navigable> {
+                // FIXME: The popup state for window.open is calculated after this call (somehow?)
+                //        Probably want to deviate from the spec and pass the popup state in here
+                auto hints = WebViewHints {
+                    .popup = window_type != WindowType::ExistingOrNone,
+                };
+                auto [page, window_handle] = traversable_navigable()->page().client().page_did_request_new_web_view(ActivateTab::Yes, hints, no_opener);
+                auto traversable = TraversableNavigable::create_a_new_top_level_traversable(*page, opener, target_name).release_value_but_fixme_should_propagate_errors();
+                page->set_top_level_traversable(traversable);
+                traversable->set_window_handle(window_handle);
+                return traversable;
+            };
+            auto create_new_traversable = JS::create_heap_function(heap(), move(create_new_traversable_closure));
+
             // 7. If noopener is true, then set chosen to the result of creating a new top-level traversable given null and targetName.
             if (no_opener == TokenizedFeature::NoOpener::Yes) {
-                // FIXME: This should do something similar to RemoteBrowsingContext -- but RemoteTraversableNavigable instead
-                TODO();
+                chosen = create_new_traversable->function()(nullptr);
             }
 
             // 8. Otherwise:
             else {
                 // 1. Set chosen to the result of creating a new top-level traversable given currentNavigable's active browsing context and targetName.
-                // FIXME: Make this method return WebIDL::ExceptionOr<ChosenNavigable>
-                chosen = TraversableNavigable::create_a_new_top_level_traversable(traversable_navigable()->page(), active_browsing_context(), target_name).release_value_but_fixme_should_propagate_errors();
+                chosen = create_new_traversable->function()(active_browsing_context());
 
                 // FIXME: 2. If sandboxingFlagSet's sandboxed navigation browsing context flag is set,
                 //    then set chosen's active browsing context's one permitted sandboxed navigator to currentNavigable's active browsing context.

+ 5 - 0
Userland/Libraries/LibWeb/HTML/TraversableNavigable.h

@@ -82,6 +82,9 @@ public:
     Page& page() { return m_page; }
     Page const& page() const { return m_page; }
 
+    String window_handle() const { return m_window_handle; }
+    void set_window_handle(String window_handle) { m_window_handle = move(window_handle); }
+
 private:
     TraversableNavigable(JS::NonnullGCPtr<Page>);
 
@@ -114,6 +117,8 @@ private:
     SessionHistoryTraversalQueue m_session_history_traversal_queue;
 
     JS::NonnullGCPtr<Page> m_page;
+
+    String m_window_handle;
 };
 
 struct BrowsingContextAndDocument {

+ 6 - 1
Userland/Libraries/LibWeb/Page/Page.h

@@ -32,6 +32,7 @@
 #include <LibWeb/HTML/ActivateTab.h>
 #include <LibWeb/HTML/ColorPickerUpdateState.h>
 #include <LibWeb/HTML/SelectItem.h>
+#include <LibWeb/HTML/TokenizedFeatures.h>
 #include <LibWeb/HTML/WebViewHints.h>
 #include <LibWeb/Loader/FileRequest.h>
 #include <LibWeb/PixelUnits.h>
@@ -269,7 +270,11 @@ public:
     virtual void page_did_set_cookie(const AK::URL&, Cookie::ParsedCookie const&, Cookie::Source) { }
     virtual void page_did_update_cookie(Web::Cookie::Cookie) { }
     virtual void page_did_update_resource_count(i32) { }
-    virtual String page_did_request_new_web_view(HTML::ActivateTab, HTML::WebViewHints, Optional<u64> = {}) { return {}; }
+    struct NewWebViewResult {
+        JS::GCPtr<Page> page;
+        String window_handle;
+    };
+    virtual NewWebViewResult page_did_request_new_web_view(HTML::ActivateTab, HTML::WebViewHints, HTML::TokenizedFeature::NoOpener) { return {}; }
     virtual void page_did_request_activate_tab() { }
     virtual void page_did_close_browsing_context(HTML::BrowsingContext const&) { }
 

+ 14 - 3
Userland/Services/WebContent/PageClient.cpp

@@ -497,14 +497,25 @@ void PageClient::page_did_update_resource_count(i32 count_waiting)
     client().async_did_update_resource_count(count_waiting);
 }
 
-String PageClient::page_did_request_new_web_view(Web::HTML::ActivateTab activate_tab, Web::HTML::WebViewHints hints, Optional<u64> page_index)
+PageClient::NewWebViewResult PageClient::page_did_request_new_web_view(Web::HTML::ActivateTab activate_tab, Web::HTML::WebViewHints hints, Web::HTML::TokenizedFeature::NoOpener no_opener)
 {
-    auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::DidRequestNewWebView>(activate_tab, hints, page_index);
+    auto& new_client = m_owner.create_page();
+
+    Optional<u64> page_id;
+    if (no_opener == Web::HTML::TokenizedFeature::NoOpener::Yes) {
+        // FIXME: Create an abstraction to let this WebContent process know about a new process we create?
+        // FIXME: For now, just create a new page in the same process anyway
+    }
+
+    page_id = new_client.m_id;
+
+    auto response = client().send_sync_but_allow_failure<Messages::WebContentClient::DidRequestNewWebView>(activate_tab, hints, page_id);
     if (!response) {
         dbgln("WebContent client disconnected during DidRequestNewWebView. Exiting peacefully.");
         exit(0);
     }
-    return response->take_handle();
+
+    return { &new_client.page(), response->take_handle() };
 }
 
 void PageClient::page_did_request_activate_tab()

+ 1 - 1
Userland/Services/WebContent/PageClient.h

@@ -118,7 +118,7 @@ private:
     virtual void page_did_set_cookie(const URL&, Web::Cookie::ParsedCookie const&, Web::Cookie::Source) override;
     virtual void page_did_update_cookie(Web::Cookie::Cookie) override;
     virtual void page_did_update_resource_count(i32) override;
-    virtual String page_did_request_new_web_view(Web::HTML::ActivateTab, Web::HTML::WebViewHints, Optional<u64> page_index = {}) override;
+    virtual NewWebViewResult page_did_request_new_web_view(Web::HTML::ActivateTab, Web::HTML::WebViewHints, Web::HTML::TokenizedFeature::NoOpener) override;
     virtual void page_did_request_activate_tab() override;
     virtual void page_did_close_browsing_context(Web::HTML::BrowsingContext const&) override;
     virtual void request_file(Web::FileRequest) override;