Explorar o código

LibWeb: Give web workers a (totally hacky) Window object

This is *not* according to spec, however we currently store prototypes
and constructors on Window, so the only way for objects in a worker
context to become fully formed is to make a Window.

Long-term we should clean this up and remove the worker window object,
but for now it allows workers to exist without asserting.
Andreas Kling %!s(int64=2) %!d(string=hai) anos
pai
achega
e97cc671ea

+ 10 - 11
Userland/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.h

@@ -12,23 +12,20 @@
 
 namespace Web::HTML {
 
-// FIXME: This is a bit ugly, this implementation is basically a 1:1 copy of what is in ESO
-//        just modified to use DOM::Document instead of HTML::Window since workers have no window
 class WorkerEnvironmentSettingsObject final
     : public EnvironmentSettingsObject
     , public Weakable<WorkerEnvironmentSettingsObject> {
 public:
-    WorkerEnvironmentSettingsObject(DOM::Document& document, NonnullOwnPtr<JS::ExecutionContext> execution_context)
+    WorkerEnvironmentSettingsObject(NonnullOwnPtr<JS::ExecutionContext> execution_context)
         : EnvironmentSettingsObject(move(execution_context))
-        , m_document(JS::make_handle(document))
     {
     }
 
-    static WeakPtr<WorkerEnvironmentSettingsObject> setup(DOM::Document& document, NonnullOwnPtr<JS::ExecutionContext> execution_context /* FIXME: null or an environment reservedEnvironment, a URL topLevelCreationURL, and an origin topLevelOrigin */)
+    static WeakPtr<WorkerEnvironmentSettingsObject> setup(NonnullOwnPtr<JS::ExecutionContext> execution_context /* FIXME: null or an environment reservedEnvironment, a URL topLevelCreationURL, and an origin topLevelOrigin */)
     {
         auto* realm = execution_context->realm;
         VERIFY(realm);
-        auto settings_object = adopt_own(*new WorkerEnvironmentSettingsObject(document, move(execution_context)));
+        auto settings_object = adopt_own(*new WorkerEnvironmentSettingsObject(move(execution_context)));
         settings_object->target_browsing_context = nullptr;
         realm->set_host_defined(move(settings_object));
 
@@ -37,14 +34,16 @@ public:
 
     virtual ~WorkerEnvironmentSettingsObject() override = default;
 
-    JS::GCPtr<DOM::Document> responsible_document() override { return m_document.ptr(); }
-    String api_url_character_encoding() override { return m_document->encoding_or_default(); }
-    AK::URL api_base_url() override { return m_document->url(); }
-    Origin origin() override { return m_document->origin(); }
+    JS::GCPtr<DOM::Document> responsible_document() override { return nullptr; }
+    String api_url_character_encoding() override { return m_api_url_character_encoding; }
+    AK::URL api_base_url() override { return m_url; }
+    Origin origin() override { return m_origin; }
     CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() override { TODO(); }
 
 private:
-    JS::Handle<DOM::Document> m_document;
+    String m_api_url_character_encoding;
+    AK::URL m_url;
+    HTML::Origin m_origin;
 };
 
 }

+ 8 - 7
Userland/Libraries/LibWeb/HTML/Worker.cpp

@@ -34,8 +34,6 @@ void Worker::visit_edges(Cell::Visitor& visitor)
 {
     Base::visit_edges(visitor);
     visitor.visit(m_document.ptr());
-    visitor.visit(m_worker_realm.ptr());
-    visitor.visit(m_worker_scope.ptr());
     visitor.visit(m_implicit_port.ptr());
     visitor.visit(m_outside_port.ptr());
 }
@@ -129,6 +127,11 @@ void Worker::run_a_worker(AK::URL& url, EnvironmentSettingsObject& outside_setti
 
     auto& console_object = *realm_execution_context->realm->intrinsics().console_object();
     m_worker_realm = realm_execution_context->realm;
+
+    // FIXME: Remove this once we don't need a hack Window (for prototypes and constructors) in workers anymore.
+    m_worker_window = HTML::Window::create(*m_worker_realm);
+    m_worker_realm->set_global_object(m_worker_scope, nullptr);
+
     m_console = adopt_ref(*new WorkerDebugConsoleClient(console_object.console()));
     console_object.console().set_client(*m_console);
 
@@ -159,8 +162,7 @@ void Worker::run_a_worker(AK::URL& url, EnvironmentSettingsObject& outside_setti
                 MessageEventInit event_init {};
                 event_init.data = message;
                 event_init.origin = "<origin>";
-                // FIXME: The cast here is totally bogus, since workers don't have a Window object..
-                dispatch_event(*MessageEvent::create(verify_cast<HTML::Window>(*m_worker_scope), HTML::EventNames::message, event_init));
+                dispatch_event(*MessageEvent::create(*m_worker_window, HTML::EventNames::message, event_init));
             }));
 
             return JS::js_undefined();
@@ -172,7 +174,7 @@ void Worker::run_a_worker(AK::URL& url, EnvironmentSettingsObject& outside_setti
 
     // 9. Set up a worker environment settings object with realm execution context,
     //    outside settings, and unsafeWorkerCreationTime, and let inside settings be the result.
-    m_inner_settings = WorkerEnvironmentSettingsObject::setup(*m_document, move(realm_execution_context));
+    m_inner_settings = WorkerEnvironmentSettingsObject::setup(move(realm_execution_context));
 
     // 10. Set worker global scope's name to the value of options's name member.
     // FIXME: name property requires the SharedWorkerGlobalScope or DedicatedWorkerGlobalScope child class to be used
@@ -257,8 +259,7 @@ void Worker::run_a_worker(AK::URL& url, EnvironmentSettingsObject& outside_setti
             // FIXME: Global scope association
 
             // 16. Let inside port be a new MessagePort object in inside settings's Realm.
-            // FIXME: The cast here is totally bogus, since workers don't have a Window object..
-            auto inside_port = MessagePort::create(verify_cast<HTML::Window>(*m_worker_scope));
+            auto inside_port = MessagePort::create(*m_worker_window);
 
             // 17. Associate inside port with worker global scope.
             // FIXME: Global scope association

+ 7 - 2
Userland/Libraries/LibWeb/HTML/Worker.h

@@ -80,13 +80,18 @@ private:
     NonnullOwnPtr<JS::Interpreter> m_interpreter;
     WeakPtr<WorkerEnvironmentSettingsObject> m_inner_settings;
     JS::VM::InterpreterExecutionScope m_interpreter_scope;
-    JS::GCPtr<JS::Realm> m_worker_realm;
     RefPtr<WorkerDebugConsoleClient> m_console;
-    JS::GCPtr<JS::Object> m_worker_scope;
 
     JS::NonnullGCPtr<MessagePort> m_implicit_port;
     JS::GCPtr<MessagePort> m_outside_port;
 
+    // NOTE: These are inside the worker VM.
+    JS::GCPtr<JS::Realm> m_worker_realm;
+    JS::GCPtr<JS::Object> m_worker_scope;
+    // FIXME: This is a mega-hack but necessary because HTML::Window holds all the prototypes and constructors.
+    //        There should be *no* Window object in a Worker context.
+    JS::GCPtr<HTML::Window> m_worker_window;
+
     void run_a_worker(AK::URL& url, EnvironmentSettingsObject& outside_settings, MessagePort& outside_port, WorkerOptions const options);
 };