From d527c5df5d3c8847ca0f483c7dc46b8d157c8781 Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Mon, 18 Nov 2024 22:49:00 +1300 Subject: [PATCH] LibWeb: Allow using queuing strategies on globals other than Window These interfaces are exposed on *, meaning it should work for workers and our newly added shadow realm global object by being stored on the universal global scope mixin. --- .../LibWeb/HTML/ShadowRealmGlobalScope.cpp | 1 + .../LibWeb/HTML/UniversalGlobalScope.cpp | 53 +++++++++++++++++++ Libraries/LibWeb/HTML/UniversalGlobalScope.h | 13 +++++ Libraries/LibWeb/HTML/Window.cpp | 49 +---------------- Libraries/LibWeb/HTML/Window.h | 9 ---- Libraries/LibWeb/HTML/WorkerGlobalScope.cpp | 1 + .../Streams/ByteLengthQueuingStrategy.cpp | 6 ++- .../LibWeb/Streams/CountQueuingStrategy.cpp | 6 ++- .../Streams/QueuingStrategy-same-instance.txt | 2 + .../QueuingStrategy-same-instance.html | 10 ++++ 10 files changed, 89 insertions(+), 61 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/Streams/QueuingStrategy-same-instance.txt create mode 100644 Tests/LibWeb/Text/input/Streams/QueuingStrategy-same-instance.html diff --git a/Libraries/LibWeb/HTML/ShadowRealmGlobalScope.cpp b/Libraries/LibWeb/HTML/ShadowRealmGlobalScope.cpp index 9f41f9281c8..2851e4a49b1 100644 --- a/Libraries/LibWeb/HTML/ShadowRealmGlobalScope.cpp +++ b/Libraries/LibWeb/HTML/ShadowRealmGlobalScope.cpp @@ -41,6 +41,7 @@ void ShadowRealmGlobalScope::initialize_web_interfaces() void ShadowRealmGlobalScope::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); + UniversalGlobalScopeMixin::visit_edges(visitor); } } diff --git a/Libraries/LibWeb/HTML/UniversalGlobalScope.cpp b/Libraries/LibWeb/HTML/UniversalGlobalScope.cpp index 771410c6f52..959373da36f 100644 --- a/Libraries/LibWeb/HTML/UniversalGlobalScope.cpp +++ b/Libraries/LibWeb/HTML/UniversalGlobalScope.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,12 @@ namespace Web::HTML { UniversalGlobalScopeMixin::~UniversalGlobalScopeMixin() = default; +void UniversalGlobalScopeMixin::visit_edges(GC::Cell::Visitor& visitor) +{ + visitor.visit(m_count_queuing_strategy_size_function); + visitor.visit(m_byte_length_queuing_strategy_size_function); +} + // https://html.spec.whatwg.org/multipage/webappapis.html#dom-btoa WebIDL::ExceptionOr UniversalGlobalScopeMixin::btoa(String const& data) const { @@ -101,4 +108,50 @@ WebIDL::ExceptionOr UniversalGlobalScopeMixin::structured_clone(JS::V return deserialized; } +// https://streams.spec.whatwg.org/#count-queuing-strategy-size-function +GC::Ref UniversalGlobalScopeMixin::count_queuing_strategy_size_function() +{ + auto& realm = HTML::relevant_realm(this_impl()); + + if (!m_count_queuing_strategy_size_function) { + // 1. Let steps be the following steps: + auto steps = [](auto const&) { + // 1. Return 1. + return 1.0; + }; + + // 2. Let F be ! CreateBuiltinFunction(steps, 0, "size", « », globalObject’s relevant Realm). + auto function = JS::NativeFunction::create(realm, move(steps), 0, "size", &realm); + + // 3. Set globalObject’s count queuing strategy size function to a Function that represents a reference to F, with callback context equal to globalObject’s relevant settings object. + m_count_queuing_strategy_size_function = realm.create(*function, relevant_settings_object(this_impl())); + } + + return GC::Ref { *m_count_queuing_strategy_size_function }; +} + +// https://streams.spec.whatwg.org/#byte-length-queuing-strategy-size-function +GC::Ref UniversalGlobalScopeMixin::byte_length_queuing_strategy_size_function() +{ + auto& realm = HTML::relevant_realm(this_impl()); + + if (!m_byte_length_queuing_strategy_size_function) { + // 1. Let steps be the following steps, given chunk: + auto steps = [](JS::VM& vm) { + auto chunk = vm.argument(0); + + // 1. Return ? GetV(chunk, "byteLength"). + return chunk.get(vm, vm.names.byteLength); + }; + + // 2. Let F be ! CreateBuiltinFunction(steps, 1, "size", « », globalObject’s relevant Realm). + auto function = JS::NativeFunction::create(realm, move(steps), 1, "size", &realm); + + // 3. Set globalObject’s byte length queuing strategy size function to a Function that represents a reference to F, with callback context equal to globalObject’s relevant settings object. + m_byte_length_queuing_strategy_size_function = realm.create(*function, relevant_settings_object(this_impl())); + } + + return GC::Ref { *m_byte_length_queuing_strategy_size_function }; +} + } diff --git a/Libraries/LibWeb/HTML/UniversalGlobalScope.h b/Libraries/LibWeb/HTML/UniversalGlobalScope.h index 62c45de89b4..0d40d3cbd4a 100644 --- a/Libraries/LibWeb/HTML/UniversalGlobalScope.h +++ b/Libraries/LibWeb/HTML/UniversalGlobalScope.h @@ -28,6 +28,19 @@ public: WebIDL::ExceptionOr atob(String const& data) const; void queue_microtask(WebIDL::CallbackType&); WebIDL::ExceptionOr structured_clone(JS::Value, StructuredSerializeOptions const&) const; + + GC::Ref count_queuing_strategy_size_function(); + GC::Ref byte_length_queuing_strategy_size_function(); + +protected: + void visit_edges(GC::Cell::Visitor&); + +private: + // https://streams.spec.whatwg.org/#count-queuing-strategy-size-function + GC::Ptr m_count_queuing_strategy_size_function; + + // https://streams.spec.whatwg.org/#byte-length-queuing-strategy-size-function + GC::Ptr m_byte_length_queuing_strategy_size_function; }; } diff --git a/Libraries/LibWeb/HTML/Window.cpp b/Libraries/LibWeb/HTML/Window.cpp index a6fe298d457..7184cd9d360 100644 --- a/Libraries/LibWeb/HTML/Window.cpp +++ b/Libraries/LibWeb/HTML/Window.cpp @@ -116,6 +116,7 @@ void Window::visit_edges(JS::Cell::Visitor& visitor) { Base::visit_edges(visitor); WindowOrWorkerGlobalScopeMixin::visit_edges(visitor); + UniversalGlobalScopeMixin::visit_edges(visitor); visitor.visit(m_associated_document); visitor.visit(m_current_event); @@ -127,8 +128,6 @@ void Window::visit_edges(JS::Cell::Visitor& visitor) visitor.visit(m_animation_frame_callback_driver); visitor.visit(m_pdf_viewer_plugin_objects); visitor.visit(m_pdf_viewer_mime_type_objects); - visitor.visit(m_count_queuing_strategy_size_function); - visitor.visit(m_byte_length_queuing_strategy_size_function); visitor.visit(m_close_watcher_manager); } @@ -662,52 +661,6 @@ Vector> Window::pdf_viewer_mime_type_objects() return m_pdf_viewer_mime_type_objects; } -// https://streams.spec.whatwg.org/#count-queuing-strategy-size-function -GC::Ref Window::count_queuing_strategy_size_function() -{ - auto& realm = this->realm(); - - if (!m_count_queuing_strategy_size_function) { - // 1. Let steps be the following steps: - auto steps = [](auto const&) { - // 1. Return 1. - return 1.0; - }; - - // 2. Let F be ! CreateBuiltinFunction(steps, 0, "size", « », globalObject’s relevant Realm). - auto function = JS::NativeFunction::create(realm, move(steps), 0, "size", &realm); - - // 3. Set globalObject’s count queuing strategy size function to a Function that represents a reference to F, with callback context equal to globalObject’s relevant settings object. - m_count_queuing_strategy_size_function = realm.create(*function, relevant_settings_object(*this)); - } - - return GC::Ref { *m_count_queuing_strategy_size_function }; -} - -// https://streams.spec.whatwg.org/#byte-length-queuing-strategy-size-function -GC::Ref Window::byte_length_queuing_strategy_size_function() -{ - auto& realm = this->realm(); - - if (!m_byte_length_queuing_strategy_size_function) { - // 1. Let steps be the following steps, given chunk: - auto steps = [](JS::VM& vm) { - auto chunk = vm.argument(0); - - // 1. Return ? GetV(chunk, "byteLength"). - return chunk.get(vm, vm.names.byteLength); - }; - - // 2. Let F be ! CreateBuiltinFunction(steps, 1, "size", « », globalObject’s relevant Realm). - auto function = JS::NativeFunction::create(realm, move(steps), 1, "size", &realm); - - // 3. Set globalObject’s byte length queuing strategy size function to a Function that represents a reference to F, with callback context equal to globalObject’s relevant settings object. - m_byte_length_queuing_strategy_size_function = realm.create(*function, relevant_settings_object(*this)); - } - - return GC::Ref { *m_byte_length_queuing_strategy_size_function }; -} - static bool s_inspector_object_exposed = false; static bool s_internals_object_exposed = false; diff --git a/Libraries/LibWeb/HTML/Window.h b/Libraries/LibWeb/HTML/Window.h index 5ef06b9cb09..ec522e69d36 100644 --- a/Libraries/LibWeb/HTML/Window.h +++ b/Libraries/LibWeb/HTML/Window.h @@ -141,9 +141,6 @@ public: CrossOriginPropertyDescriptorMap const& cross_origin_property_descriptor_map() const { return m_cross_origin_property_descriptor_map; } CrossOriginPropertyDescriptorMap& cross_origin_property_descriptor_map() { return m_cross_origin_property_descriptor_map; } - GC::Ref count_queuing_strategy_size_function(); - GC::Ref byte_length_queuing_strategy_size_function(); - // JS API functions GC::Ref window() const; GC::Ref self() const; @@ -313,12 +310,6 @@ private: // https://html.spec.whatwg.org/multipage/interaction.html#last-history-action-activation-timestamp HighResolutionTime::DOMHighResTimeStamp m_last_history_action_activation_timestamp { AK::Infinity }; - // https://streams.spec.whatwg.org/#count-queuing-strategy-size-function - GC::Ptr m_count_queuing_strategy_size_function; - - // https://streams.spec.whatwg.org/#byte-length-queuing-strategy-size-function - GC::Ptr m_byte_length_queuing_strategy_size_function; - // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-status // When the Window object is created, the attribute must be set to the empty string. It does not do anything else. String m_status; diff --git a/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp b/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp index 198830a9072..db3c8883e5b 100644 --- a/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp +++ b/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp @@ -45,6 +45,7 @@ void WorkerGlobalScope::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); WindowOrWorkerGlobalScopeMixin::visit_edges(visitor); + UniversalGlobalScopeMixin::visit_edges(visitor); visitor.visit(m_location); visitor.visit(m_navigator); diff --git a/Libraries/LibWeb/Streams/ByteLengthQueuingStrategy.cpp b/Libraries/LibWeb/Streams/ByteLengthQueuingStrategy.cpp index ca38178aa51..e8476f6641e 100644 --- a/Libraries/LibWeb/Streams/ByteLengthQueuingStrategy.cpp +++ b/Libraries/LibWeb/Streams/ByteLengthQueuingStrategy.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace Web::Streams { @@ -34,7 +34,9 @@ ByteLengthQueuingStrategy::~ByteLengthQueuingStrategy() = default; GC::Ref ByteLengthQueuingStrategy::size() { // 1. Return this's relevant global object's byte length queuing strategy size function. - return verify_cast(HTML::relevant_global_object(*this)).byte_length_queuing_strategy_size_function(); + auto* global = dynamic_cast(&HTML::relevant_global_object(*this)); + VERIFY(global); + return global->byte_length_queuing_strategy_size_function(); } void ByteLengthQueuingStrategy::initialize(JS::Realm& realm) diff --git a/Libraries/LibWeb/Streams/CountQueuingStrategy.cpp b/Libraries/LibWeb/Streams/CountQueuingStrategy.cpp index c0a4e7c2147..fa923dbc705 100644 --- a/Libraries/LibWeb/Streams/CountQueuingStrategy.cpp +++ b/Libraries/LibWeb/Streams/CountQueuingStrategy.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace Web::Streams { @@ -34,7 +34,9 @@ CountQueuingStrategy::~CountQueuingStrategy() = default; GC::Ref CountQueuingStrategy::size() { // 1. Return this's relevant global object's count queuing strategy size function. - return verify_cast(HTML::relevant_global_object(*this)).count_queuing_strategy_size_function(); + auto* global = dynamic_cast(&HTML::relevant_global_object(*this)); + VERIFY(global); + return global->count_queuing_strategy_size_function(); } void CountQueuingStrategy::initialize(JS::Realm& realm) diff --git a/Tests/LibWeb/Text/expected/Streams/QueuingStrategy-same-instance.txt b/Tests/LibWeb/Text/expected/Streams/QueuingStrategy-same-instance.txt new file mode 100644 index 00000000000..e1ec01a3c72 --- /dev/null +++ b/Tests/LibWeb/Text/expected/Streams/QueuingStrategy-same-instance.txt @@ -0,0 +1,2 @@ +CountQueuingStrategy | size1 === size2 -> true +ByteLengthQueuingStrategy | size1 === size2 -> true diff --git a/Tests/LibWeb/Text/input/Streams/QueuingStrategy-same-instance.html b/Tests/LibWeb/Text/input/Streams/QueuingStrategy-same-instance.html new file mode 100644 index 00000000000..a97a728ae16 --- /dev/null +++ b/Tests/LibWeb/Text/input/Streams/QueuingStrategy-same-instance.html @@ -0,0 +1,10 @@ + +