From 2c3531ab78c5c9ef9fa05a666ec29ecf284961ab Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Fri, 25 Oct 2024 12:38:19 -0600 Subject: [PATCH] LibWeb: Move JS::Promise <-> WebIDL conversion into IDL This change also removes as much direct use of JS::Promise in LibWeb as possible. When specs refer to `Promise` they should be assumed to be referring to the WebIDL Promise type, not the JS::Promise type. The one exception is the HostPromiseRejectionTracker hook on the JS VM. This facility and its associated sets and events are intended to expose the exact opaque object handles that were rejected to author code. This is not possible with the WebIDL Promise type, so we have to use JS::Promise or JS::Object to hold onto the promises. It also exposes which specs need some updates in the area of promises. WebDriver stands out in this regard. WebAudio could use some more cross-references to WebIDL as well to clarify things. --- .../BindingsGenerator/IDLGenerators.cpp | 29 +++++++++----- .../Libraries/LibWeb/Animations/Animation.h | 4 +- .../Libraries/LibWeb/CSS/CSSStyleSheet.cpp | 21 ++++++---- Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h | 2 +- Userland/Libraries/LibWeb/CSS/FontFace.cpp | 6 +-- Userland/Libraries/LibWeb/CSS/FontFace.h | 4 +- Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp | 10 ++--- Userland/Libraries/LibWeb/CSS/FontFaceSet.h | 6 +-- .../LibWeb/CSS/ScreenOrientation.cpp | 2 +- .../Libraries/LibWeb/CSS/ScreenOrientation.h | 2 +- .../Libraries/LibWeb/Clipboard/Clipboard.cpp | 4 +- .../Libraries/LibWeb/Clipboard/Clipboard.h | 2 +- .../Libraries/LibWeb/Crypto/SubtleCrypto.cpp | 40 +++++++++---------- .../Libraries/LibWeb/Crypto/SubtleCrypto.h | 20 +++++----- Userland/Libraries/LibWeb/Fetch/Body.cpp | 16 ++++---- Userland/Libraries/LibWeb/Fetch/Body.h | 14 +++---- .../Libraries/LibWeb/Fetch/FetchMethod.cpp | 8 ++-- Userland/Libraries/LibWeb/Fetch/FetchMethod.h | 2 +- Userland/Libraries/LibWeb/FileAPI/Blob.cpp | 6 +-- Userland/Libraries/LibWeb/FileAPI/Blob.h | 6 +-- .../Libraries/LibWeb/FileAPI/FileReader.cpp | 21 ++++++---- .../CustomElements/CustomElementRegistry.cpp | 22 ++++------ .../CustomElements/CustomElementRegistry.h | 4 +- .../LibWeb/HTML/HTMLImageElement.cpp | 4 +- .../Libraries/LibWeb/HTML/HTMLImageElement.h | 2 +- .../LibWeb/HTML/HTMLMediaElement.cpp | 4 +- .../Libraries/LibWeb/HTML/HTMLMediaElement.h | 2 +- Userland/Libraries/LibWeb/HTML/Navigation.cpp | 25 ++++++------ Userland/Libraries/LibWeb/HTML/Navigation.h | 5 +-- .../LibWeb/HTML/NavigationTransition.cpp | 6 +-- .../LibWeb/HTML/NavigationTransition.h | 8 ++-- .../Scripting/TemporaryExecutionContext.h | 1 + .../LibWeb/HTML/ServiceWorkerContainer.cpp | 4 +- .../LibWeb/HTML/ServiceWorkerContainer.h | 2 +- .../LibWeb/HTML/WindowOrWorkerGlobalScope.cpp | 38 +++++++++++------- .../LibWeb/HTML/WindowOrWorkerGlobalScope.h | 8 ++-- .../LibWeb/Streams/AbstractOperations.cpp | 40 ++++++++----------- .../LibWeb/Streams/AbstractOperations.h | 2 +- .../LibWeb/Streams/ReadableStream.cpp | 19 ++++----- .../Libraries/LibWeb/Streams/ReadableStream.h | 4 +- .../Streams/ReadableStreamBYOBReader.cpp | 4 +- .../LibWeb/Streams/ReadableStreamBYOBReader.h | 2 +- .../Streams/ReadableStreamDefaultReader.cpp | 4 +- .../Streams/ReadableStreamDefaultReader.h | 2 +- .../Streams/ReadableStreamGenericReader.cpp | 9 ++--- .../Streams/ReadableStreamGenericReader.h | 4 +- .../LibWeb/Streams/WritableStream.cpp | 14 +++---- .../Libraries/LibWeb/Streams/WritableStream.h | 4 +- .../Streams/WritableStreamDefaultWriter.cpp | 28 ++++++------- .../Streams/WritableStreamDefaultWriter.h | 10 ++--- .../LibWeb/WebAssembly/WebAssembly.cpp | 30 +++++++------- .../LibWeb/WebAssembly/WebAssembly.h | 6 +-- .../LibWeb/WebAudio/AudioContext.cpp | 18 ++++----- .../Libraries/LibWeb/WebAudio/AudioContext.h | 6 +-- .../LibWeb/WebAudio/BaseAudioContext.cpp | 4 +- .../LibWeb/WebAudio/BaseAudioContext.h | 2 +- .../LibWeb/WebAudio/OfflineAudioContext.cpp | 6 +-- .../LibWeb/WebAudio/OfflineAudioContext.h | 6 +-- .../LibWeb/WebDriver/ExecuteScript.cpp | 20 +++++----- Userland/Libraries/LibWeb/WebIDL/Promise.cpp | 17 ++++---- Userland/Libraries/LibWeb/WebIDL/Promise.h | 8 ++-- 61 files changed, 323 insertions(+), 306 deletions(-) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index 3fd931666d5..a0dc6e4f4b3 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -665,16 +665,17 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter } } } else if (parameter.type->name() == "Promise") { - // NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved - // Promise is defined in the spec; https://webidl.spec.whatwg.org/#idl-promise doesn't say - // anything of this sort. Both Gecko and Blink do it, however, so I'm sure it's correct. + // https://webidl.spec.whatwg.org/#js-promise scoped_generator.append(R"~~~( - if (!@js_name@@js_suffix@.is_object() || !is(@js_name@@js_suffix@.as_object())) { - auto new_promise = JS::Promise::create(realm); - new_promise->fulfill(@js_name@@js_suffix@); - @js_name@@js_suffix@ = new_promise; + if (!@js_name@@js_suffix@.is_cell() || !is(@js_name@@js_suffix@.as_cell())) { + // 1. Let promiseCapability be ? NewPromiseCapability(%Promise%). + auto promise_capability = TRY(JS::new_promise_capability(vm, realm.intrinsics().promise_constructor())); + // 2. Perform ? Call(promiseCapability.[[Resolve]], undefined, « V »). + TRY(JS::call(vm, *promise_capability->resolve(), JS::js_undefined(), @js_name@@js_suffix@)); + // 3. Return promiseCapability. + @js_name@@js_suffix@ = promise_capability; } - auto @cpp_name@ = JS::make_handle(&static_cast(@js_name@@js_suffix@.as_object())); + auto @cpp_name@ = JS::make_handle(static_cast(@js_name@@js_suffix@.as_cell())); )~~~"); } else if (parameter.type->name() == "object") { if (parameter.type->is_nullable()) { @@ -1794,9 +1795,13 @@ static void generate_wrap_statement(SourceGenerator& generator, ByteString const } } else if (type.is_integer()) { generate_from_integral(scoped_generator, type); - } else if (type.name() == "Location" || type.name() == "Promise" || type.name() == "Uint8Array" || type.name() == "Uint8ClampedArray" || type.name() == "any") { + } else if (type.name() == "Location" || type.name() == "Uint8Array" || type.name() == "Uint8ClampedArray" || type.name() == "any") { scoped_generator.append(R"~~~( @result_expression@ @value@; +)~~~"); + } else if (type.name() == "Promise") { + scoped_generator.append(R"~~~( + @result_expression@ JS::NonnullGCPtr { verify_cast(*@value@->promise()) }; )~~~"); } else if (type.name() == "ArrayBufferView" || type.name() == "BufferSource") { scoped_generator.append(R"~~~( @@ -4243,6 +4248,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu #include #include #include +#include #include #include #include @@ -4254,6 +4260,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu #include #include #include +#include #include #include @@ -4663,6 +4670,7 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu #include #include #include +#include #include #include #include @@ -4682,8 +4690,9 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu #include #include #include -#include #include +#include +#include #include #if __has_include() diff --git a/Userland/Libraries/LibWeb/Animations/Animation.h b/Userland/Libraries/LibWeb/Animations/Animation.h index 41be019afc1..860628a6843 100644 --- a/Userland/Libraries/LibWeb/Animations/Animation.h +++ b/Userland/Libraries/LibWeb/Animations/Animation.h @@ -60,10 +60,10 @@ public: bool pending() const { return m_pending_play_task == TaskState::Scheduled || m_pending_pause_task == TaskState::Scheduled; } // https://www.w3.org/TR/web-animations-1/#dom-animation-ready - JS::NonnullGCPtr ready() const { return *current_ready_promise()->promise(); } + JS::NonnullGCPtr ready() const { return current_ready_promise(); } // https://www.w3.org/TR/web-animations-1/#dom-animation-finished - JS::NonnullGCPtr finished() const { return *current_finished_promise()->promise(); } + JS::NonnullGCPtr finished() const { return current_finished_promise(); } bool is_finished() const { return m_is_finished; } JS::GCPtr onfinish(); diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp index 04ad50f3c48..d33fda45083 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -186,19 +187,21 @@ WebIDL::ExceptionOr CSSStyleSheet::delete_rule(unsigned index) } // https://drafts.csswg.org/cssom/#dom-cssstylesheet-replace -JS::NonnullGCPtr CSSStyleSheet::replace(String text) +JS::NonnullGCPtr CSSStyleSheet::replace(String text) { + auto& realm = this->realm(); + // 1. Let promise be a promise - auto promise = JS::Promise::create(realm()); + auto promise = WebIDL::create_promise(realm); // 2. If the constructed flag is not set, or the disallow modification flag is set, reject promise with a NotAllowedError DOMException and return promise. if (!constructed()) { - promise->reject(WebIDL::NotAllowedError::create(realm(), "Can't call replace() on non-constructed stylesheets"_string)); + WebIDL::reject_promise(realm, promise, WebIDL::NotAllowedError::create(realm, "Can't call replace() on non-constructed stylesheets"_string)); return promise; } if (disallow_modification()) { - promise->reject(WebIDL::NotAllowedError::create(realm(), "Can't call replace() on non-modifiable stylesheets"_string)); + WebIDL::reject_promise(realm, promise, WebIDL::NotAllowedError::create(realm, "Can't call replace() on non-modifiable stylesheets"_string)); return promise; } @@ -206,14 +209,16 @@ JS::NonnullGCPtr CSSStyleSheet::replace(String text) set_disallow_modification(true); // 4. In parallel, do these steps: - Platform::EventLoopPlugin::the().deferred_invoke([this, text = move(text), promise] { + Platform::EventLoopPlugin::the().deferred_invoke([&realm, this, text = move(text), promise = JS::Handle(promise)] { + HTML::TemporaryExecutionContext execution_context { HTML::relevant_settings_object(*this), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; + // 1. Let rules be the result of running parse a stylesheet’s contents from text. - auto context = m_style_sheet_list ? CSS::Parser::ParsingContext { m_style_sheet_list->document() } : CSS::Parser::ParsingContext { realm() }; + auto context = m_style_sheet_list ? CSS::Parser::ParsingContext { m_style_sheet_list->document() } : CSS::Parser::ParsingContext { realm }; auto* parsed_stylesheet = parse_css_stylesheet(context, text); auto& rules = parsed_stylesheet->rules(); // 2. If rules contains one or more @import rules, remove those rules from rules. - JS::MarkedVector> rules_without_import(realm().heap()); + JS::MarkedVector> rules_without_import(realm.heap()); for (auto rule : rules) { if (rule->type() != CSSRule::Type::Import) rules_without_import.append(rule); @@ -226,7 +231,7 @@ JS::NonnullGCPtr CSSStyleSheet::replace(String text) set_disallow_modification(false); // 5. Resolve promise with sheet. - promise->fulfill(this); + WebIDL::resolve_promise(realm, *promise, this); }); return promise; diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h index 86f91a3b0f4..eaac750dec5 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h @@ -53,7 +53,7 @@ public: WebIDL::ExceptionOr remove_rule(Optional index); WebIDL::ExceptionOr delete_rule(unsigned index); - JS::NonnullGCPtr replace(String text); + JS::NonnullGCPtr replace(String text); WebIDL::ExceptionOr replace_sync(StringView text); void for_each_effective_rule(TraversalOrder, Function const& callback) const; diff --git a/Userland/Libraries/LibWeb/CSS/FontFace.cpp b/Userland/Libraries/LibWeb/CSS/FontFace.cpp index 635cb5ed554..0a090ebc0cc 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFace.cpp +++ b/Userland/Libraries/LibWeb/CSS/FontFace.cpp @@ -205,9 +205,9 @@ void FontFace::visit_edges(JS::Cell::Visitor& visitor) visitor.visit(m_font_status_promise); } -JS::NonnullGCPtr FontFace::loaded() const +JS::NonnullGCPtr FontFace::loaded() const { - return verify_cast(*m_font_status_promise->promise()); + return m_font_status_promise; } // https://drafts.csswg.org/css-font-loading/#dom-fontface-family @@ -320,7 +320,7 @@ WebIDL::ExceptionOr FontFace::set_line_gap_override(String const&) } // https://drafts.csswg.org/css-font-loading/#dom-fontface-load -JS::NonnullGCPtr FontFace::load() +JS::NonnullGCPtr FontFace::load() { // 1. Let font face be the FontFace object on which this method was called. auto& font_face = *this; diff --git a/Userland/Libraries/LibWeb/CSS/FontFace.h b/Userland/Libraries/LibWeb/CSS/FontFace.h index 3e577feea22..c074ebb8400 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFace.h +++ b/Userland/Libraries/LibWeb/CSS/FontFace.h @@ -74,8 +74,8 @@ public: Bindings::FontFaceLoadStatus status() const { return m_status; } - JS::NonnullGCPtr load(); - JS::NonnullGCPtr loaded() const; + JS::NonnullGCPtr load(); + JS::NonnullGCPtr loaded() const; void load_font_source(); diff --git a/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp b/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp index 4b7d061f5a5..3cd3dd19cf9 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp +++ b/Userland/Libraries/LibWeb/CSS/FontFaceSet.cpp @@ -227,7 +227,7 @@ static WebIDL::ExceptionOr> find_matching_font_faces(J } // https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-load -JS::ThrowCompletionOr> FontFaceSet::load(String const& font, String const& text) +JS::ThrowCompletionOr> FontFaceSet::load(String const& font, String const& text) { auto& realm = this->realm(); @@ -278,18 +278,18 @@ JS::ThrowCompletionOr> FontFaceSet::load(String co }); // 2. Return promise. Complete the rest of these steps asynchronously. - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } // https://drafts.csswg.org/css-font-loading/#font-face-set-ready -JS::NonnullGCPtr FontFaceSet::ready() const +JS::NonnullGCPtr FontFaceSet::ready() const { - return verify_cast(*m_ready_promise->promise()); + return m_ready_promise; } void FontFaceSet::resolve_ready_promise() { - WebIDL::resolve_promise(realm(), *m_ready_promise); + WebIDL::resolve_promise(realm(), m_ready_promise); } } diff --git a/Userland/Libraries/LibWeb/CSS/FontFaceSet.h b/Userland/Libraries/LibWeb/CSS/FontFaceSet.h index 2b9a4d170be..9cd6e5c34cc 100644 --- a/Userland/Libraries/LibWeb/CSS/FontFaceSet.h +++ b/Userland/Libraries/LibWeb/CSS/FontFaceSet.h @@ -38,9 +38,9 @@ public: void set_onloadingerror(WebIDL::CallbackType*); WebIDL::CallbackType* onloadingerror(); - JS::ThrowCompletionOr> load(String const& font, String const& text); + JS::ThrowCompletionOr> load(String const& font, String const& text); - JS::NonnullGCPtr ready() const; + JS::NonnullGCPtr ready() const; Bindings::FontFaceSetLoadStatus status() const { return m_status; } void resolve_ready_promise(); @@ -52,7 +52,7 @@ private: virtual void visit_edges(Cell::Visitor&) override; JS::NonnullGCPtr m_set_entries; - JS::GCPtr m_ready_promise; // [[ReadyPromise]] + JS::NonnullGCPtr m_ready_promise; // [[ReadyPromise]] Vector> m_loading_fonts {}; // [[LoadingFonts]] Vector> m_loaded_fonts {}; // [[LoadedFonts]] diff --git a/Userland/Libraries/LibWeb/CSS/ScreenOrientation.cpp b/Userland/Libraries/LibWeb/CSS/ScreenOrientation.cpp index 4d641059eaa..c0b0ed04af2 100644 --- a/Userland/Libraries/LibWeb/CSS/ScreenOrientation.cpp +++ b/Userland/Libraries/LibWeb/CSS/ScreenOrientation.cpp @@ -30,7 +30,7 @@ JS::NonnullGCPtr ScreenOrientation::create(JS::Realm& realm) } // https://w3c.github.io/screen-orientation/#lock-method -WebIDL::ExceptionOr> ScreenOrientation::lock(Bindings::OrientationLockType) +WebIDL::ExceptionOr> ScreenOrientation::lock(Bindings::OrientationLockType) { return WebIDL::NotSupportedError::create(realm(), "FIXME: ScreenOrientation::lock() is not implemented"_string); } diff --git a/Userland/Libraries/LibWeb/CSS/ScreenOrientation.h b/Userland/Libraries/LibWeb/CSS/ScreenOrientation.h index 9c839ddc7cc..263dfa0365b 100644 --- a/Userland/Libraries/LibWeb/CSS/ScreenOrientation.h +++ b/Userland/Libraries/LibWeb/CSS/ScreenOrientation.h @@ -20,7 +20,7 @@ class ScreenOrientation final : public DOM::EventTarget { public: [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&); - WebIDL::ExceptionOr> lock(Bindings::OrientationLockType); + WebIDL::ExceptionOr> lock(Bindings::OrientationLockType); void unlock(); Bindings::OrientationType type() const; WebIDL::UnsignedShort angle() const; diff --git a/Userland/Libraries/LibWeb/Clipboard/Clipboard.cpp b/Userland/Libraries/LibWeb/Clipboard/Clipboard.cpp index 8aa4191e373..92162ff415b 100644 --- a/Userland/Libraries/LibWeb/Clipboard/Clipboard.cpp +++ b/Userland/Libraries/LibWeb/Clipboard/Clipboard.cpp @@ -142,7 +142,7 @@ static bool check_clipboard_write_permission(JS::Realm& realm) } // https://w3c.github.io/clipboard-apis/#dom-clipboard-writetext -JS::NonnullGCPtr Clipboard::write_text(String data) +JS::NonnullGCPtr Clipboard::write_text(String data) { // 1. Let realm be this's relevant realm. auto& realm = HTML::relevant_realm(*this); @@ -194,7 +194,7 @@ JS::NonnullGCPtr Clipboard::write_text(String data) }); // 4. Return p. - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } } diff --git a/Userland/Libraries/LibWeb/Clipboard/Clipboard.h b/Userland/Libraries/LibWeb/Clipboard/Clipboard.h index 761379e487c..4efa1de3ba0 100644 --- a/Userland/Libraries/LibWeb/Clipboard/Clipboard.h +++ b/Userland/Libraries/LibWeb/Clipboard/Clipboard.h @@ -23,7 +23,7 @@ public: static WebIDL::ExceptionOr> construct_impl(JS::Realm&); virtual ~Clipboard() override; - JS::NonnullGCPtr write_text(String); + JS::NonnullGCPtr write_text(String); private: Clipboard(JS::Realm&); diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp index bc03d3fd8b3..8e218153db7 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp @@ -121,7 +121,7 @@ WebIDL::ExceptionOr normalize_an_algorithm(JS:: } // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-encrypt -JS::NonnullGCPtr SubtleCrypto::encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter) +JS::NonnullGCPtr SubtleCrypto::encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter) { auto& realm = this->realm(); auto& vm = this->vm(); @@ -174,11 +174,11 @@ JS::NonnullGCPtr SubtleCrypto::encrypt(AlgorithmIdentifier const& a WebIDL::resolve_promise(realm, promise, cipher_text.release_value()); }); - return verify_cast(*promise->promise()); + return promise; } // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-decrypt -JS::NonnullGCPtr SubtleCrypto::decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter) +JS::NonnullGCPtr SubtleCrypto::decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter) { auto& realm = this->realm(); auto& vm = this->vm(); @@ -231,11 +231,11 @@ JS::NonnullGCPtr SubtleCrypto::decrypt(AlgorithmIdentifier const& a WebIDL::resolve_promise(realm, promise, plain_text.release_value()); }); - return verify_cast(*promise->promise()); + return promise; } // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest -JS::NonnullGCPtr SubtleCrypto::digest(AlgorithmIdentifier const& algorithm, JS::Handle const& data) +JS::NonnullGCPtr SubtleCrypto::digest(AlgorithmIdentifier const& algorithm, JS::Handle const& data) { auto& realm = this->realm(); auto& vm = this->vm(); @@ -279,11 +279,11 @@ JS::NonnullGCPtr SubtleCrypto::digest(AlgorithmIdentifier const& al WebIDL::resolve_promise(realm, promise, result.release_value()); }); - return verify_cast(*promise->promise()); + return promise; } // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-generateKey -JS::ThrowCompletionOr> SubtleCrypto::generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector key_usages) +JS::ThrowCompletionOr> SubtleCrypto::generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector key_usages) { auto& realm = this->realm(); @@ -339,11 +339,11 @@ JS::ThrowCompletionOr> SubtleCrypto::generate_key( }); }); - return verify_cast(*promise->promise()); + return promise; } // https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey -JS::ThrowCompletionOr> SubtleCrypto::import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector key_usages) +JS::ThrowCompletionOr> SubtleCrypto::import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector key_usages) { auto& realm = this->realm(); @@ -415,11 +415,11 @@ JS::ThrowCompletionOr> SubtleCrypto::import_key(Bi WebIDL::resolve_promise(realm, promise, result); }); - return verify_cast(*promise->promise()); + return promise; } // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-exportKey -JS::ThrowCompletionOr> SubtleCrypto::export_key(Bindings::KeyFormat format, JS::NonnullGCPtr key) +JS::ThrowCompletionOr> SubtleCrypto::export_key(Bindings::KeyFormat format, JS::NonnullGCPtr key) { auto& realm = this->realm(); // 1. Let format and key be the format and key parameters passed to the exportKey() method, respectively. @@ -461,11 +461,11 @@ JS::ThrowCompletionOr> SubtleCrypto::export_key(Bi WebIDL::resolve_promise(realm, promise, result_or_error.release_value()); }); - return verify_cast(*promise->promise()); + return promise; } // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-sign -JS::ThrowCompletionOr> SubtleCrypto::sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter) +JS::ThrowCompletionOr> SubtleCrypto::sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter) { auto& realm = this->realm(); auto& vm = this->vm(); @@ -518,11 +518,11 @@ JS::ThrowCompletionOr> SubtleCrypto::sign(Algorith WebIDL::resolve_promise(realm, promise, result.release_value()); }); - return verify_cast(*promise->promise()); + return promise; } // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-verify -JS::ThrowCompletionOr> SubtleCrypto::verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& signature_data, JS::Handle const& data_parameter) +JS::ThrowCompletionOr> SubtleCrypto::verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& signature_data, JS::Handle const& data_parameter) { auto& realm = this->realm(); auto& vm = this->vm(); @@ -582,11 +582,11 @@ JS::ThrowCompletionOr> SubtleCrypto::verify(Algori WebIDL::resolve_promise(realm, promise, result.release_value()); }); - return verify_cast(*promise->promise()); + return promise; } // https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits -JS::ThrowCompletionOr> SubtleCrypto::derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, u32 length) +JS::ThrowCompletionOr> SubtleCrypto::derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, u32 length) { auto& realm = this->realm(); // 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length parameters passed to the deriveBits() method, respectively. @@ -629,10 +629,10 @@ JS::ThrowCompletionOr> SubtleCrypto::derive_bits(A WebIDL::resolve_promise(realm, promise, result.release_value()); }); - return verify_cast(*promise->promise()); + return promise; } -JS::ThrowCompletionOr> SubtleCrypto::derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector key_usages) +JS::ThrowCompletionOr> SubtleCrypto::derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector key_usages) { auto& realm = this->realm(); auto& vm = this->vm(); @@ -722,7 +722,7 @@ JS::ThrowCompletionOr> SubtleCrypto::derive_key(Al WebIDL::resolve_promise(realm, promise, result.release_value()); }); - return verify_cast(*promise->promise()); + return promise; } SupportedAlgorithmsMap& supported_algorithms_internal() diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h index 5109e7cd24d..5c83a1101a9 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h @@ -27,19 +27,19 @@ public: virtual ~SubtleCrypto() override; - JS::NonnullGCPtr encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter); - JS::NonnullGCPtr decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter); - JS::ThrowCompletionOr> sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter); - JS::ThrowCompletionOr> verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& signature, JS::Handle const& data_parameter); + JS::NonnullGCPtr encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter); + JS::NonnullGCPtr decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter); + JS::ThrowCompletionOr> sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& data_parameter); + JS::ThrowCompletionOr> verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr key, JS::Handle const& signature, JS::Handle const& data_parameter); - JS::NonnullGCPtr digest(AlgorithmIdentifier const& algorithm, JS::Handle const& data); + JS::NonnullGCPtr digest(AlgorithmIdentifier const& algorithm, JS::Handle const& data); - JS::ThrowCompletionOr> generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector key_usages); - JS::ThrowCompletionOr> derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, u32 length); - JS::ThrowCompletionOr> derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector key_usages); + JS::ThrowCompletionOr> generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector key_usages); + JS::ThrowCompletionOr> derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, u32 length); + JS::ThrowCompletionOr> derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector key_usages); - JS::ThrowCompletionOr> import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector key_usages); - JS::ThrowCompletionOr> export_key(Bindings::KeyFormat format, JS::NonnullGCPtr key); + JS::ThrowCompletionOr> import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector key_usages); + JS::ThrowCompletionOr> export_key(Bindings::KeyFormat format, JS::NonnullGCPtr key); private: explicit SubtleCrypto(JS::Realm&); diff --git a/Userland/Libraries/LibWeb/Fetch/Body.cpp b/Userland/Libraries/LibWeb/Fetch/Body.cpp index fd11cfc1638..55227dba128 100644 --- a/Userland/Libraries/LibWeb/Fetch/Body.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Body.cpp @@ -55,7 +55,7 @@ bool BodyMixin::body_used() const } // https://fetch.spec.whatwg.org/#dom-body-arraybuffer -WebIDL::ExceptionOr> BodyMixin::array_buffer() const +WebIDL::ExceptionOr> BodyMixin::array_buffer() const { auto& vm = Bindings::main_thread_vm(); auto& realm = *vm.current_realm(); @@ -65,7 +65,7 @@ WebIDL::ExceptionOr> BodyMixin::array_buffer() con } // https://fetch.spec.whatwg.org/#dom-body-blob -WebIDL::ExceptionOr> BodyMixin::blob() const +WebIDL::ExceptionOr> BodyMixin::blob() const { auto& vm = Bindings::main_thread_vm(); auto& realm = *vm.current_realm(); @@ -75,7 +75,7 @@ WebIDL::ExceptionOr> BodyMixin::blob() const } // https://fetch.spec.whatwg.org/#dom-body-bytes -WebIDL::ExceptionOr> BodyMixin::bytes() const +WebIDL::ExceptionOr> BodyMixin::bytes() const { auto& vm = Bindings::main_thread_vm(); auto& realm = *vm.current_realm(); @@ -85,7 +85,7 @@ WebIDL::ExceptionOr> BodyMixin::bytes() const } // https://fetch.spec.whatwg.org/#dom-body-formdata -WebIDL::ExceptionOr> BodyMixin::form_data() const +WebIDL::ExceptionOr> BodyMixin::form_data() const { auto& vm = Bindings::main_thread_vm(); auto& realm = *vm.current_realm(); @@ -95,7 +95,7 @@ WebIDL::ExceptionOr> BodyMixin::form_data() const } // https://fetch.spec.whatwg.org/#dom-body-json -WebIDL::ExceptionOr> BodyMixin::json() const +WebIDL::ExceptionOr> BodyMixin::json() const { auto& vm = Bindings::main_thread_vm(); auto& realm = *vm.current_realm(); @@ -105,7 +105,7 @@ WebIDL::ExceptionOr> BodyMixin::json() const } // https://fetch.spec.whatwg.org/#dom-body-text -WebIDL::ExceptionOr> BodyMixin::text() const +WebIDL::ExceptionOr> BodyMixin::text() const { auto& vm = Bindings::main_thread_vm(); auto& realm = *vm.current_realm(); @@ -175,7 +175,7 @@ WebIDL::ExceptionOr package_data(JS::Realm& realm, ByteBuffer bytes, } // https://fetch.spec.whatwg.org/#concept-body-consume-body -WebIDL::ExceptionOr> consume_body(JS::Realm& realm, BodyMixin const& object, PackageDataType type) +WebIDL::ExceptionOr> consume_body(JS::Realm& realm, BodyMixin const& object, PackageDataType type) { // 1. If object is unusable, then return a promise rejected with a TypeError. if (object.is_unusable()) { @@ -229,7 +229,7 @@ WebIDL::ExceptionOr> consume_body(JS::Realm& realm } // 7. Return promise. - return JS::NonnullGCPtr { verify_cast(*promise->promise().ptr()) }; + return promise; } } diff --git a/Userland/Libraries/LibWeb/Fetch/Body.h b/Userland/Libraries/LibWeb/Fetch/Body.h index c33256f22c1..f78a35c903e 100644 --- a/Userland/Libraries/LibWeb/Fetch/Body.h +++ b/Userland/Libraries/LibWeb/Fetch/Body.h @@ -39,15 +39,15 @@ public: [[nodiscard]] bool body_used() const; // JS API functions - [[nodiscard]] WebIDL::ExceptionOr> array_buffer() const; - [[nodiscard]] WebIDL::ExceptionOr> blob() const; - [[nodiscard]] WebIDL::ExceptionOr> bytes() const; - [[nodiscard]] WebIDL::ExceptionOr> form_data() const; - [[nodiscard]] WebIDL::ExceptionOr> json() const; - [[nodiscard]] WebIDL::ExceptionOr> text() const; + [[nodiscard]] WebIDL::ExceptionOr> array_buffer() const; + [[nodiscard]] WebIDL::ExceptionOr> blob() const; + [[nodiscard]] WebIDL::ExceptionOr> bytes() const; + [[nodiscard]] WebIDL::ExceptionOr> form_data() const; + [[nodiscard]] WebIDL::ExceptionOr> json() const; + [[nodiscard]] WebIDL::ExceptionOr> text() const; }; [[nodiscard]] WebIDL::ExceptionOr package_data(JS::Realm&, ByteBuffer, PackageDataType, Optional const&); -[[nodiscard]] WebIDL::ExceptionOr> consume_body(JS::Realm&, BodyMixin const&, PackageDataType); +[[nodiscard]] WebIDL::ExceptionOr> consume_body(JS::Realm&, BodyMixin const&, PackageDataType); } diff --git a/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp b/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp index 70eb6be1fc9..e3b7f6bc216 100644 --- a/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp +++ b/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp @@ -26,7 +26,7 @@ namespace Web::Fetch { // https://fetch.spec.whatwg.org/#dom-global-fetch -JS::NonnullGCPtr fetch(JS::VM& vm, RequestInfo const& input, RequestInit const& init) +JS::NonnullGCPtr fetch(JS::VM& vm, RequestInfo const& input, RequestInit const& init) { auto& realm = *vm.current_realm(); @@ -39,7 +39,7 @@ JS::NonnullGCPtr fetch(JS::VM& vm, RequestInfo const& input, Reques if (exception_or_request_object.is_exception()) { auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, exception_or_request_object.exception()); WebIDL::reject_promise(realm, promise_capability, *throw_completion.value()); - return verify_cast(*promise_capability->promise().ptr()); + return promise_capability; } auto request_object = exception_or_request_object.release_value(); @@ -52,7 +52,7 @@ JS::NonnullGCPtr fetch(JS::VM& vm, RequestInfo const& input, Reques abort_fetch(realm, promise_capability, request, nullptr, request_object->signal()->reason()); // 2. Return p. - return verify_cast(*promise_capability->promise().ptr()); + return promise_capability; } // 5. Let globalObject be request’s client’s global object. @@ -150,7 +150,7 @@ JS::NonnullGCPtr fetch(JS::VM& vm, RequestInfo const& input, Reques }); // 13. Return p. - return verify_cast(*promise_capability->promise().ptr()); + return promise_capability; } // https://fetch.spec.whatwg.org/#abort-fetch diff --git a/Userland/Libraries/LibWeb/Fetch/FetchMethod.h b/Userland/Libraries/LibWeb/Fetch/FetchMethod.h index 77b906426cf..f6e27dd614c 100644 --- a/Userland/Libraries/LibWeb/Fetch/FetchMethod.h +++ b/Userland/Libraries/LibWeb/Fetch/FetchMethod.h @@ -14,7 +14,7 @@ namespace Web::Fetch { -JS::NonnullGCPtr fetch(JS::VM&, RequestInfo const& input, RequestInit const& init = {}); +JS::NonnullGCPtr fetch(JS::VM&, RequestInfo const& input, RequestInit const& init = {}); void abort_fetch(JS::Realm&, WebIDL::Promise const&, JS::NonnullGCPtr, JS::GCPtr, JS::Value error); } diff --git a/Userland/Libraries/LibWeb/FileAPI/Blob.cpp b/Userland/Libraries/LibWeb/FileAPI/Blob.cpp index 0c6aad5c1d3..e9fd67127ac 100644 --- a/Userland/Libraries/LibWeb/FileAPI/Blob.cpp +++ b/Userland/Libraries/LibWeb/FileAPI/Blob.cpp @@ -377,7 +377,7 @@ JS::NonnullGCPtr Blob::get_stream() } // https://w3c.github.io/FileAPI/#dom-blob-text -JS::NonnullGCPtr Blob::text() +JS::NonnullGCPtr Blob::text() { auto& realm = this->realm(); auto& vm = realm.vm(); @@ -407,7 +407,7 @@ JS::NonnullGCPtr Blob::text() } // https://w3c.github.io/FileAPI/#dom-blob-arraybuffer -JS::NonnullGCPtr Blob::array_buffer() +JS::NonnullGCPtr Blob::array_buffer() { auto& realm = this->realm(); @@ -434,7 +434,7 @@ JS::NonnullGCPtr Blob::array_buffer() } // https://w3c.github.io/FileAPI/#dom-blob-bytes -JS::NonnullGCPtr Blob::bytes() +JS::NonnullGCPtr Blob::bytes() { auto& realm = this->realm(); diff --git a/Userland/Libraries/LibWeb/FileAPI/Blob.h b/Userland/Libraries/LibWeb/FileAPI/Blob.h index 7746ea185c9..c7f240e280e 100644 --- a/Userland/Libraries/LibWeb/FileAPI/Blob.h +++ b/Userland/Libraries/LibWeb/FileAPI/Blob.h @@ -48,9 +48,9 @@ public: WebIDL::ExceptionOr> slice(Optional start = {}, Optional end = {}, Optional const& content_type = {}); JS::NonnullGCPtr stream(); - JS::NonnullGCPtr text(); - JS::NonnullGCPtr array_buffer(); - JS::NonnullGCPtr bytes(); + JS::NonnullGCPtr text(); + JS::NonnullGCPtr array_buffer(); + JS::NonnullGCPtr bytes(); ReadonlyBytes raw_bytes() const { return m_byte_buffer.bytes(); } diff --git a/Userland/Libraries/LibWeb/FileAPI/FileReader.cpp b/Userland/Libraries/LibWeb/FileAPI/FileReader.cpp index a74154ac7fc..f856495e7f9 100644 --- a/Userland/Libraries/LibWeb/FileAPI/FileReader.cpp +++ b/Userland/Libraries/LibWeb/FileAPI/FileReader.cpp @@ -147,20 +147,23 @@ WebIDL::ExceptionOr FileReader::read_operation(Blob& blob, Type type, Opti // 10. In parallel, while true: Platform::EventLoopPlugin::the().deferred_invoke([this, chunk_promise, reader, bytes, is_first_chunk, &realm, type, encoding_name, blobs_type]() mutable { - HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) }; + HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; Optional progress_timer; while (true) { auto& vm = realm.vm(); + // FIXME: Try harder to not reach into the [[Promise]] slot of chunkPromise + auto promise = JS::NonnullGCPtr { verify_cast(*chunk_promise->promise()) }; // 1. Wait for chunkPromise to be fulfilled or rejected. + // FIXME: Create spec issue to use WebIDL react to promise steps here instead of this custom logic Platform::EventLoopPlugin::the().spin_until([&]() { - return chunk_promise->state() == JS::Promise::State::Fulfilled || chunk_promise->state() == JS::Promise::State::Rejected; + return promise->state() == JS::Promise::State::Fulfilled || promise->state() == JS::Promise::State::Rejected; }); // 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr. // NOTE: ISSUE 2 We might change loadstart to be dispatched synchronously, to align with XMLHttpRequest behavior. [Issue #119] - if (chunk_promise->state() == JS::Promise::State::Fulfilled && is_first_chunk) { + if (promise->state() == JS::Promise::State::Fulfilled && is_first_chunk) { HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, &realm]() { dispatch_event(DOM::Event::create(realm, HTML::EventNames::loadstart)); })); @@ -169,14 +172,14 @@ WebIDL::ExceptionOr FileReader::read_operation(Blob& blob, Type type, Opti // 3. Set isFirstChunk to false. is_first_chunk = false; - VERIFY(chunk_promise->result().is_object()); - auto& result = chunk_promise->result().as_object(); + VERIFY(promise->result().is_object()); + auto& result = promise->result().as_object(); auto value = MUST(result.get(vm.names.value)); auto done = MUST(result.get(vm.names.done)); // 4. If chunkPromise is fulfilled with an object whose done property is false and whose value property is a Uint8Array object, run these steps: - if (chunk_promise->state() == JS::Promise::State::Fulfilled && !done.as_bool() && is(value.as_object())) { + if (promise->state() == JS::Promise::State::Fulfilled && !done.as_bool() && is(value.as_object())) { // 1. Let bs be the byte sequence represented by the Uint8Array object. auto const& byte_sequence = verify_cast(value.as_object()); @@ -200,7 +203,7 @@ WebIDL::ExceptionOr FileReader::read_operation(Blob& blob, Type type, Opti chunk_promise = reader->read(); } // 5. Otherwise, if chunkPromise is fulfilled with an object whose done property is true, queue a task to run the following steps and abort this algorithm: - else if (chunk_promise->state() == JS::Promise::State::Fulfilled && done.as_bool()) { + else if (promise->state() == JS::Promise::State::Fulfilled && done.as_bool()) { HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, bytes, type, &realm, encoding_name, blobs_type]() { // 1. Set fr’s state to "done". m_state = State::Done; @@ -234,7 +237,7 @@ WebIDL::ExceptionOr FileReader::read_operation(Blob& blob, Type type, Opti return; } // 6. Otherwise, if chunkPromise is rejected with an error error, queue a task to run the following steps and abort this algorithm: - else if (chunk_promise->state() == JS::Promise::State::Rejected) { + else if (promise->state() == JS::Promise::State::Rejected) { HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, &realm]() { // 1. Set fr’s state to "done". m_state = State::Done; @@ -250,6 +253,8 @@ WebIDL::ExceptionOr FileReader::read_operation(Blob& blob, Type type, Opti // 5. Note: Event handler for the error event could have started another load, if that happens the loadend event for this load is not fired. })); + + return; } } }); diff --git a/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp b/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp index 327b0d48ab7..2a336572fa4 100644 --- a/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp +++ b/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp @@ -313,7 +313,7 @@ JS::ThrowCompletionOr CustomElementRegistry::define(String const& name, We auto promise = promise_when_defined_iterator->value; // 2. Resolve promise with constructor. - promise->fulfill(constructor->callback); + WebIDL::resolve_promise(realm, promise, constructor->callback); // 3. Delete the entry with key name from this CustomElementRegistry's when-defined promise map. m_when_defined_promise_map.remove(name); @@ -353,40 +353,34 @@ Optional CustomElementRegistry::get_name(JS::Handle> CustomElementRegistry::when_defined(String const& name) +WebIDL::ExceptionOr> CustomElementRegistry::when_defined(String const& name) { auto& realm = this->realm(); // 1. If name is not a valid custom element name, then return a new promise rejected with a "SyntaxError" DOMException. - if (!is_valid_custom_element_name(name)) { - auto promise = JS::Promise::create(realm); - promise->reject(WebIDL::SyntaxError::create(realm, MUST(String::formatted("'{}' is not a valid custom element name"sv, name)))); - return promise; - } + if (!is_valid_custom_element_name(name)) + return WebIDL::create_rejected_promise(realm, WebIDL::SyntaxError::create(realm, MUST(String::formatted("'{}' is not a valid custom element name"sv, name)))); // 2. If this CustomElementRegistry contains an entry with name name, then return a new promise resolved with that entry's constructor. auto existing_definition_iterator = m_custom_element_definitions.find_if([&name](JS::Handle const& definition) { return definition->name() == name; }); - if (existing_definition_iterator != m_custom_element_definitions.end()) { - auto promise = JS::Promise::create(realm); - promise->fulfill((*existing_definition_iterator)->constructor().callback); - return promise; - } + if (existing_definition_iterator != m_custom_element_definitions.end()) + return WebIDL::create_resolved_promise(realm, (*existing_definition_iterator)->constructor().callback); // 3. Let map be this CustomElementRegistry's when-defined promise map. // NOTE: Not necessary. // 4. If map does not contain an entry with key name, create an entry in map with key name and whose value is a new promise. // 5. Let promise be the value of the entry in map with key name. - JS::GCPtr promise; + JS::GCPtr promise; auto existing_promise_iterator = m_when_defined_promise_map.find(name); if (existing_promise_iterator != m_when_defined_promise_map.end()) { promise = existing_promise_iterator->value; } else { - promise = JS::Promise::create(realm); + promise = WebIDL::create_promise(realm); m_when_defined_promise_map.set(name, *promise); } diff --git a/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.h b/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.h index a20785e012a..a6fc34c68bf 100644 --- a/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.h +++ b/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.h @@ -27,7 +27,7 @@ public: JS::ThrowCompletionOr define(String const& name, WebIDL::CallbackType* constructor, ElementDefinitionOptions options); Variant, JS::Value> get(String const& name) const; Optional get_name(JS::Handle const& constructor) const; - WebIDL::ExceptionOr> when_defined(String const& name); + WebIDL::ExceptionOr> when_defined(String const& name); void upgrade(JS::NonnullGCPtr root) const; JS::GCPtr get_definition_with_name_and_local_name(String const& name, String const& local_name) const; @@ -48,7 +48,7 @@ private: // https://html.spec.whatwg.org/multipage/custom-elements.html#when-defined-promise-map // Every CustomElementRegistry also has a when-defined promise map, mapping valid custom element names to promises. It is used to implement the whenDefined() method. - OrderedHashMap> m_when_defined_promise_map; + OrderedHashMap> m_when_defined_promise_map; }; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp index 1dcbc1ec183..1ac132a94ef 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp @@ -282,7 +282,7 @@ String HTMLImageElement::current_src() const } // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode -WebIDL::ExceptionOr> HTMLImageElement::decode() const +WebIDL::ExceptionOr> HTMLImageElement::decode() const { auto& realm = this->realm(); @@ -360,7 +360,7 @@ WebIDL::ExceptionOr> HTMLImageElement::decode() co }); })); - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } Optional HTMLImageElement::default_role() const diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h index c02b4d363a4..baed3ad5e38 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h @@ -61,7 +61,7 @@ public: String current_src() const; // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode - [[nodiscard]] WebIDL::ExceptionOr> decode() const; + [[nodiscard]] WebIDL::ExceptionOr> decode() const; virtual Optional default_role() const override; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index 230a4df06e2..cdf25b1d17b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -334,7 +334,7 @@ void HTMLMediaElement::set_duration(double duration) paintable->set_needs_display(); } -WebIDL::ExceptionOr> HTMLMediaElement::play() +WebIDL::ExceptionOr> HTMLMediaElement::play() { auto& realm = this->realm(); @@ -355,7 +355,7 @@ WebIDL::ExceptionOr> HTMLMediaElement::play() TRY(play_element()); // 5. Return promise. - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } // https://html.spec.whatwg.org/multipage/media.html#dom-media-pause diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h index 82e3949688a..92b0e7d6c2a 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h @@ -89,7 +89,7 @@ public: bool paused() const { return m_paused; } bool ended() const; bool potentially_playing() const; - WebIDL::ExceptionOr> play(); + WebIDL::ExceptionOr> play(); WebIDL::ExceptionOr pause(); WebIDL::ExceptionOr toggle_playback(); diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.cpp b/Userland/Libraries/LibWeb/HTML/Navigation.cpp index a97144331b9..68719f53dd2 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigation.cpp @@ -495,14 +495,13 @@ i64 Navigation::get_the_navigation_api_entry_index(SessionHistoryEntry const& sh // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-early-error-result NavigationResult Navigation::early_error_result(AnyException e) { - auto& vm = this->vm(); + auto& realm = this->realm(); // An early error result for an exception e is a NavigationResult dictionary instance given by // «[ "committed" → a promise rejected with e, "finished" → a promise rejected with e ]». - auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, e); return { - .committed = WebIDL::create_rejected_promise(realm(), *throw_completion.value())->promise(), - .finished = WebIDL::create_rejected_promise(realm(), *throw_completion.value())->promise(), + .committed = WebIDL::create_rejected_promise_from_exception(realm, e), + .finished = WebIDL::create_rejected_promise_from_exception(realm, e), }; } @@ -512,8 +511,8 @@ NavigationResult navigation_api_method_tracker_derived_result(JS::NonnullGCPtrcommitted_promise->promise(), - api_method_tracker->finished_promise->promise(), + api_method_tracker->committed_promise, + api_method_tracker->finished_promise, }; } @@ -639,8 +638,8 @@ WebIDL::ExceptionOr Navigation::perform_a_navigation_api_trave // «[ "committed" → a promise resolved with current, "finished" → a promise resolved with current ]». if (key == current->session_history_entry().navigation_api_key()) { return NavigationResult { - .committed = WebIDL::create_resolved_promise(realm, current)->promise(), - .finished = WebIDL::create_resolved_promise(realm, current)->promise() + .committed = WebIDL::create_resolved_promise(realm, current), + .finished = WebIDL::create_resolved_promise(realm, current) }; } @@ -788,7 +787,7 @@ void Navigation::abort_the_ongoing_navigation(JS::GCPtr er // 11. If navigation's transition is not null, then: if (m_transition != nullptr) { // 1. Reject navigation's transition's finished promise with error. - m_transition->finished()->reject(error); + WebIDL::reject_promise(realm, m_transition->finished(), error); // 2. Set navigation's transition to null. m_transition = nullptr; @@ -1105,10 +1104,10 @@ bool Navigation::inner_navigate_event_firing_algorithm( // 4. Set navigation's transition to a new NavigationTransition created in navigation's relevant realm, // whose navigation type is navigationType, from entry is fromNHE, and whose finished promise is a new promise // created in navigation's relevant realm. - m_transition = NavigationTransition::create(realm, navigation_type, *from_nhe, JS::Promise::create(realm)); + m_transition = NavigationTransition::create(realm, navigation_type, *from_nhe, WebIDL::create_promise(realm)); // 5. Mark as handled navigation's transition's finished promise. - m_transition->finished()->set_is_handled(); + WebIDL::mark_promise_as_handled(*m_transition->finished()); // 6. If navigationType is "traverse", then set navigation's suppress normal scroll restoration during ongoing navigation to true. // NOTE: If event's scroll behavior was set to "after-transition", then scroll restoration will happen as part of finishing @@ -1187,7 +1186,7 @@ bool Navigation::inner_navigate_event_firing_algorithm( // 8. If navigation's transition is not null, then resolve navigation's transition's finished promise with undefined. if (m_transition != nullptr) - m_transition->finished()->fulfill(JS::js_undefined()); + WebIDL::resolve_promise(realm, m_transition->finished(), JS::js_undefined()); // 9. Set navigation's transition to null. m_transition = nullptr; }, @@ -1231,7 +1230,7 @@ bool Navigation::inner_navigate_event_firing_algorithm( // 9. If navigation's transition is not null, then reject navigation's transition's finished promise with rejectionReason. if (m_transition) - m_transition->finished()->reject(rejection_reason); + WebIDL::reject_promise(realm, m_transition->finished(), rejection_reason); // 10. Set navigation's transition to null. m_transition = nullptr; diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.h b/Userland/Libraries/LibWeb/HTML/Navigation.h index 25319147e18..1246b6ebcd4 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.h +++ b/Userland/Libraries/LibWeb/HTML/Navigation.h @@ -39,9 +39,8 @@ struct NavigationReloadOptions : public NavigationOptions { // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationresult struct NavigationResult { - // FIXME: Are we supposed to return a PromiseCapability (WebIDL::Promise) here? - JS::NonnullGCPtr committed; - JS::NonnullGCPtr finished; + JS::NonnullGCPtr committed; + JS::NonnullGCPtr finished; }; // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-method-tracker diff --git a/Userland/Libraries/LibWeb/HTML/NavigationTransition.cpp b/Userland/Libraries/LibWeb/HTML/NavigationTransition.cpp index 9d953116b14..43373240858 100644 --- a/Userland/Libraries/LibWeb/HTML/NavigationTransition.cpp +++ b/Userland/Libraries/LibWeb/HTML/NavigationTransition.cpp @@ -5,23 +5,23 @@ */ #include -#include #include #include #include #include #include +#include namespace Web::HTML { JS_DEFINE_ALLOCATOR(NavigationTransition); -JS::NonnullGCPtr NavigationTransition::create(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr from_entry, JS::GCPtr finished_promise) +JS::NonnullGCPtr NavigationTransition::create(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr from_entry, JS::NonnullGCPtr finished_promise) { return realm.heap().allocate(realm, realm, navigation_type, from_entry, finished_promise); } -NavigationTransition::NavigationTransition(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr from_entry, JS::GCPtr finished_promise) +NavigationTransition::NavigationTransition(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr from_entry, JS::NonnullGCPtr finished_promise) : Bindings::PlatformObject(realm) , m_navigation_type(navigation_type) , m_from_entry(from_entry) diff --git a/Userland/Libraries/LibWeb/HTML/NavigationTransition.h b/Userland/Libraries/LibWeb/HTML/NavigationTransition.h index b049b8b8386..6fdec435679 100644 --- a/Userland/Libraries/LibWeb/HTML/NavigationTransition.h +++ b/Userland/Libraries/LibWeb/HTML/NavigationTransition.h @@ -17,7 +17,7 @@ class NavigationTransition : public Bindings::PlatformObject { JS_DECLARE_ALLOCATOR(NavigationTransition); public: - [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr, JS::GCPtr); + [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr, JS::NonnullGCPtr); // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationtransition-navigationtype Bindings::NavigationType navigation_type() const { return m_navigation_type; } @@ -26,12 +26,12 @@ public: JS::NonnullGCPtr from() const { return m_from_entry; } // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationtransition-finished - JS::GCPtr finished() const { return m_finished_promise; } + JS::NonnullGCPtr finished() const { return m_finished_promise; } virtual ~NavigationTransition() override; private: - NavigationTransition(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr, JS::GCPtr); + NavigationTransition(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr, JS::NonnullGCPtr); virtual void initialize(JS::Realm&) override; virtual void visit_edges(JS::Cell::Visitor&) override; @@ -43,7 +43,7 @@ private: JS::NonnullGCPtr m_from_entry; // https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-navigationtransition-finished - JS::GCPtr m_finished_promise; + JS::NonnullGCPtr m_finished_promise; }; } diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/TemporaryExecutionContext.h b/Userland/Libraries/LibWeb/HTML/Scripting/TemporaryExecutionContext.h index 88dc90f7c4e..dc260b26c5a 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/TemporaryExecutionContext.h +++ b/Userland/Libraries/LibWeb/HTML/Scripting/TemporaryExecutionContext.h @@ -6,6 +6,7 @@ #pragma once +#include #include namespace Web::HTML { diff --git a/Userland/Libraries/LibWeb/HTML/ServiceWorkerContainer.cpp b/Userland/Libraries/LibWeb/HTML/ServiceWorkerContainer.cpp index aeb6f0cf714..57a0e9f4663 100644 --- a/Userland/Libraries/LibWeb/HTML/ServiceWorkerContainer.cpp +++ b/Userland/Libraries/LibWeb/HTML/ServiceWorkerContainer.cpp @@ -44,7 +44,7 @@ JS::NonnullGCPtr ServiceWorkerContainer::create(JS::Real } // https://w3c.github.io/ServiceWorker/#navigator-service-worker-register -JS::NonnullGCPtr ServiceWorkerContainer::register_(String script_url, RegistrationOptions const& options) +JS::NonnullGCPtr ServiceWorkerContainer::register_(String script_url, RegistrationOptions const& options) { auto& realm = this->realm(); // Note: The register(scriptURL, options) method creates or updates a service worker registration for the given scope url. @@ -76,7 +76,7 @@ JS::NonnullGCPtr ServiceWorkerContainer::register_(String script_ur start_register(scope_url, parsed_script_url, p, client, client->creation_url, options.type, options.update_via_cache); // 8. Return p. - return verify_cast(*p->promise()); + return p; } // https://w3c.github.io/ServiceWorker/#start-register-algorithm diff --git a/Userland/Libraries/LibWeb/HTML/ServiceWorkerContainer.h b/Userland/Libraries/LibWeb/HTML/ServiceWorkerContainer.h index 18dc26ed418..707a9db1979 100644 --- a/Userland/Libraries/LibWeb/HTML/ServiceWorkerContainer.h +++ b/Userland/Libraries/LibWeb/HTML/ServiceWorkerContainer.h @@ -34,7 +34,7 @@ public: [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm& realm); virtual ~ServiceWorkerContainer() override; - JS::NonnullGCPtr register_(String script_url, RegistrationOptions const& options); + JS::NonnullGCPtr register_(String script_url, RegistrationOptions const& options); #undef __ENUMERATE #define __ENUMERATE(attribute_name, event_name) \ diff --git a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp index bee9b77ff64..b9b975afa11 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp +++ b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -166,25 +167,26 @@ void WindowOrWorkerGlobalScopeMixin::queue_microtask(WebIDL::CallbackType& callb } // https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-createimagebitmap -JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, Optional options) const +JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, Optional options) const { return create_image_bitmap_impl(image, {}, {}, {}, {}, options); } // https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-createimagebitmap -JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional options) const +JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional options) const { return create_image_bitmap_impl(image, sx, sy, sw, sh, options); } -JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitmap_impl(ImageBitmapSource& image, Optional sx, Optional sy, Optional sw, Optional sh, Optional& options) const +JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitmap_impl(ImageBitmapSource& image, Optional sx, Optional sy, Optional sw, Optional sh, Optional& options) const { + auto& realm = this_impl().realm(); + // 1. If either sw or sh is given and is 0, then return a promise rejected with a RangeError. if (sw == 0 || sh == 0) { - auto promise = JS::Promise::create(this_impl().realm()); auto error_message = MUST(String::formatted("{} is an invalid value for {}", sw == 0 ? *sw : *sh, sw == 0 ? "sw"sv : "sh"sv)); - promise->reject(JS::RangeError::create(this_impl().realm(), move(error_message))); - return promise; + auto error = JS::RangeError::create(realm, move(error_message)); + return WebIDL::create_rejected_promise(realm, move(error)); } // FIXME: @@ -195,14 +197,13 @@ JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitma // FIXME: "Check the usability of the image argument" is only defined for CanvasImageSource, let's skip it for other types if (image.has()) { if (auto usability = check_usability_of_image(image.get()); usability.is_error() or usability.value() == CanvasImageSourceUsability::Bad) { - auto promise = JS::Promise::create(this_impl().realm()); - promise->reject(WebIDL::InvalidStateError::create(this_impl().realm(), "image argument is not usable"_string)); - return promise; + auto error = WebIDL::InvalidStateError::create(this_impl().realm(), "image argument is not usable"_string); + return WebIDL::create_rejected_promise_from_exception(realm, error); } } // 4. Let p be a new promise. - auto p = JS::Promise::create(this_impl().realm()); + auto p = WebIDL::create_promise(realm); // 5. Let imageBitmap be a new ImageBitmap object. auto image_bitmap = ImageBitmap::create(this_impl().realm()); @@ -226,7 +227,9 @@ JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitma // imageData is corrupted in some fatal way such that the image dimensions cannot be obtained // (e.g., a vector graphic with no natural size), then reject p with an "InvalidStateError" DOMException // and abort these steps. - p->reject(WebIDL::InvalidStateError::create(relevant_realm(*p), "image does not contain a supported image format"_string)); + auto& realm = relevant_realm(p->promise()); + TemporaryExecutionContext context { relevant_settings_object(p->promise()), TemporaryExecutionContext::CallbacksEnabled::Yes }; + WebIDL::reject_promise(realm, *p, WebIDL::InvalidStateError::create(realm, "image does not contain a supported image format"_string)); }; auto on_successful_decode = [image_bitmap = JS::Handle(*image_bitmap), p = JS::Handle(*p)](Web::Platform::DecodedImage& result) -> ErrorOr { @@ -236,8 +239,11 @@ JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitma // or is disabled), or, if there is no such image, the first frame of the animation. image_bitmap->set_bitmap(result.frames.take_first().bitmap); + auto& realm = relevant_realm(p->promise()); + // 5. Resolve p with imageBitmap. - p->fulfill(image_bitmap); + TemporaryExecutionContext context { relevant_settings_object(*image_bitmap), TemporaryExecutionContext::CallbacksEnabled::Yes }; + WebIDL::resolve_promise(realm, *p, image_bitmap); return {}; }; @@ -248,7 +254,9 @@ JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::create_image_bitma dbgln("(STUBBED) createImageBitmap() for non-blob types"); (void)sx; (void)sy; - p->reject(JS::Error::create(relevant_realm(*p), "Not Implemented: createImageBitmap() for non-blob types"sv)); + auto error = JS::Error::create(realm, "Not Implemented: createImageBitmap() for non-blob types"sv); + TemporaryExecutionContext context { relevant_settings_object(p->promise()), TemporaryExecutionContext::CallbacksEnabled::Yes }; + WebIDL::reject_promise(realm, *p, error); }); // 7. Return p. @@ -273,7 +281,7 @@ WebIDL::ExceptionOr WindowOrWorkerGlobalScopeMixin::structured_clone( return deserialized; } -JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::fetch(Fetch::RequestInfo const& input, Fetch::RequestInit const& init) const +JS::NonnullGCPtr WindowOrWorkerGlobalScopeMixin::fetch(Fetch::RequestInfo const& input, Fetch::RequestInit const& init) const { auto& vm = this_impl().vm(); return Fetch::fetch(vm, input, init); @@ -926,7 +934,7 @@ void WindowOrWorkerGlobalScopeMixin::notify_about_rejected_promises(Badgeresult(), }; diff --git a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h index 5414c0b1163..ca387655013 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h +++ b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h @@ -39,10 +39,10 @@ public: WebIDL::ExceptionOr btoa(String const& data) const; WebIDL::ExceptionOr atob(String const& data) const; void queue_microtask(WebIDL::CallbackType&); - JS::NonnullGCPtr create_image_bitmap(ImageBitmapSource image, Optional options = {}) const; - JS::NonnullGCPtr create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional options = {}) const; + JS::NonnullGCPtr create_image_bitmap(ImageBitmapSource image, Optional options = {}) const; + JS::NonnullGCPtr create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional options = {}) const; WebIDL::ExceptionOr structured_clone(JS::Value, StructuredSerializeOptions const&) const; - JS::NonnullGCPtr fetch(Fetch::RequestInfo const&, Fetch::RequestInit const&) const; + JS::NonnullGCPtr fetch(Fetch::RequestInfo const&, Fetch::RequestInit const&) const; i32 set_timeout(TimerHandler, i32 timeout, JS::MarkedVector arguments); i32 set_interval(TimerHandler, i32 timeout, JS::MarkedVector arguments); @@ -105,7 +105,7 @@ private: i32 run_timer_initialization_steps(TimerHandler handler, i32 timeout, JS::MarkedVector arguments, Repeat repeat, Optional previous_id = {}); void run_steps_after_a_timeout_impl(i32 timeout, Function completion_step, Optional timer_key = {}); - JS::NonnullGCPtr create_image_bitmap_impl(ImageBitmapSource& image, Optional sx, Optional sy, Optional sw, Optional sh, Optional& options) const; + JS::NonnullGCPtr create_image_bitmap_impl(ImageBitmapSource& image, Optional sx, Optional sy, Optional sw, Optional sh, Optional& options) const; IDAllocator m_timer_id_allocator; HashMap> m_timers; diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp index 97174cd619e..589cb1f609d 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp @@ -131,7 +131,7 @@ JS::NonnullGCPtr readable_stream_cancel(ReadableStream& stream, JS::create_heap_function(stream.heap(), [](JS::Value) -> WebIDL::ExceptionOr { return JS::js_undefined(); }), {}); - return WebIDL::create_resolved_promise(realm, react_result); + return react_result; } // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request @@ -431,9 +431,9 @@ public: // 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]). auto cancel_result = readable_stream_cancel(m_stream, completion.value().value()); - JS::NonnullGCPtr cancel_value = verify_cast(*cancel_result->promise().ptr()); - WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_value); + // Note: We need to manually convert the result to an ECMAScript value here, by extracting its [[Promise]] slot. + WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_result->promise()); // 4. Return. return; @@ -584,8 +584,7 @@ WebIDL::ExceptionOr readable_stream_default_tee(JS::Realm& r auto cancel_result = readable_stream_cancel(stream, composite_reason); // 3. Resolve cancelPromise with cancelResult. - JS::NonnullGCPtr cancel_value = verify_cast(*cancel_result->promise().ptr()); - WebIDL::resolve_promise(realm, cancel_promise, cancel_value); + WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise()); } // 4. Return cancelPromise. @@ -609,8 +608,7 @@ WebIDL::ExceptionOr readable_stream_default_tee(JS::Realm& r auto cancel_result = readable_stream_cancel(stream, composite_reason); // 3. Resolve cancelPromise with cancelResult. - JS::NonnullGCPtr cancel_value = verify_cast(*cancel_result->promise().ptr()); - WebIDL::resolve_promise(realm, cancel_promise, cancel_value); + WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise()); } // 4. Return cancelPromise. @@ -744,9 +742,8 @@ public: // 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]). auto cancel_result = readable_stream_cancel(m_stream, completion.value().value()); - JS::NonnullGCPtr cancel_value = verify_cast(*cancel_result->promise().ptr()); - WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_value); + WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_result->promise()); // 4. Return. return; @@ -909,9 +906,8 @@ public: // 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]). auto cancel_result = readable_stream_cancel(m_stream, completion.value().value()); - JS::NonnullGCPtr cancel_value = verify_cast(*cancel_result->promise().ptr()); - WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_value); + WebIDL::resolve_promise(m_realm, m_cancel_promise, cancel_result->promise()); // 4. Return. return; @@ -1221,8 +1217,7 @@ WebIDL::ExceptionOr readable_byte_stream_tee(JS::Realm& real auto cancel_result = readable_stream_cancel(stream, composite_reason); // 3. Resolve cancelPromise with cancelResult. - JS::NonnullGCPtr cancel_value = verify_cast(*cancel_result->promise().ptr()); - WebIDL::resolve_promise(realm, cancel_promise, cancel_value); + WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise()); } // 4. Return cancelPromise. @@ -1246,8 +1241,7 @@ WebIDL::ExceptionOr readable_byte_stream_tee(JS::Realm& real auto cancel_result = readable_stream_cancel(stream, composite_reason); // 3. Resolve cancelPromise with cancelResult. - JS::NonnullGCPtr cancel_value = verify_cast(*cancel_result->promise().ptr()); - WebIDL::resolve_promise(realm, cancel_promise, cancel_value); + WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise()); } // 4. Return cancelPromise. @@ -1442,7 +1436,7 @@ WebIDL::ExceptionOr> readable_stream_from_itera }), {}); - return WebIDL::create_resolved_promise(realm, react_result); + return react_result; }); // 5. Let cancelAlgorithm be the following steps, given reason: @@ -1483,7 +1477,7 @@ WebIDL::ExceptionOr> readable_stream_from_itera }), {}); - return WebIDL::create_resolved_promise(realm, react_result); + return react_result; }); // 6. Set stream to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, 0). @@ -4711,7 +4705,7 @@ void writable_stream_default_controller_write(WritableStreamDefaultController& c } // https://streams.spec.whatwg.org/#initialize-transform-stream -void initialize_transform_stream(TransformStream& stream, JS::NonnullGCPtr start_promise, double writable_high_water_mark, JS::NonnullGCPtr writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr readable_size_algorithm) +void initialize_transform_stream(TransformStream& stream, JS::NonnullGCPtr start_promise, double writable_high_water_mark, JS::NonnullGCPtr writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr readable_size_algorithm) { auto& realm = stream.realm(); @@ -4970,7 +4964,7 @@ JS::NonnullGCPtr transform_stream_default_controller_perform_tr return JS::throw_completion(reason); })); - return WebIDL::create_resolved_promise(realm, react_result); + return react_result; } // https://streams.spec.whatwg.org/#transform-stream-default-sink-abort-algorithm @@ -5031,7 +5025,7 @@ JS::NonnullGCPtr transform_stream_default_sink_abort_algorithm( })); // 8. Return controller.[[finishPromise]]. - return JS::NonnullGCPtr { *controller->finish_promise() }; + return *controller->finish_promise(); } // https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm @@ -5075,7 +5069,7 @@ JS::NonnullGCPtr transform_stream_default_sink_close_algorithm( return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, readable->stored_error().as_string().utf8_string() }; })); - return WebIDL::create_resolved_promise(realm, react_result); + return react_result; } // https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm @@ -5118,7 +5112,7 @@ JS::NonnullGCPtr transform_stream_default_sink_write_algorithm( }), {}); - return WebIDL::create_resolved_promise(realm, react_result); + return react_result; } // 4. Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk). @@ -5196,7 +5190,7 @@ JS::NonnullGCPtr transform_stream_default_source_cancel_algorit })); // 8. Return controller.[[finishPromise]]. - return JS::NonnullGCPtr { *controller->finish_promise() }; + return *controller->finish_promise(); } // https://streams.spec.whatwg.org/#transform-stream-error diff --git a/Userland/Libraries/LibWeb/Streams/AbstractOperations.h b/Userland/Libraries/LibWeb/Streams/AbstractOperations.h index 30ca7ed6e38..437edb5c9b5 100644 --- a/Userland/Libraries/LibWeb/Streams/AbstractOperations.h +++ b/Userland/Libraries/LibWeb/Streams/AbstractOperations.h @@ -168,7 +168,7 @@ void writable_stream_default_controller_process_close(WritableStreamDefaultContr void writable_stream_default_controller_process_write(WritableStreamDefaultController&, JS::Value chunk); void writable_stream_default_controller_write(WritableStreamDefaultController&, JS::Value chunk, JS::Value chunk_size); -void initialize_transform_stream(TransformStream&, JS::NonnullGCPtr start_promise, double writable_high_water_mark, JS::NonnullGCPtr writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr readable_size_algorithm); +void initialize_transform_stream(TransformStream&, JS::NonnullGCPtr start_promise, double writable_high_water_mark, JS::NonnullGCPtr writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr readable_size_algorithm); void set_up_transform_stream_default_controller(TransformStream&, TransformStreamDefaultController&, JS::NonnullGCPtr, JS::NonnullGCPtr, JS::NonnullGCPtr); void set_up_transform_stream_default_controller_from_transformer(TransformStream&, JS::Value transformer, Transformer&); void transform_stream_default_controller_clear_algorithms(TransformStreamDefaultController&); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp index a5dc13cd196..748aeae8fbb 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.cpp @@ -90,18 +90,18 @@ bool ReadableStream::locked() const } // https://streams.spec.whatwg.org/#rs-cancel -JS::NonnullGCPtr ReadableStream::cancel(JS::Value reason) +JS::NonnullGCPtr ReadableStream::cancel(JS::Value reason) { auto& realm = this->realm(); // 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception. if (is_readable_stream_locked(*this)) { auto exception = JS::TypeError::create(realm, "Cannot cancel a locked stream"sv); - return WebIDL::create_rejected_promise(realm, JS::Value { exception })->promise(); + return WebIDL::create_rejected_promise(realm, exception); } // 2. Return ! ReadableStreamCancel(this, reason). - return readable_stream_cancel(*this, reason)->promise(); + return readable_stream_cancel(*this, reason); } // https://streams.spec.whatwg.org/#rs-get-reader @@ -141,29 +141,26 @@ WebIDL::ExceptionOr> ReadableStream::pipe_throu return JS::NonnullGCPtr { *transform.readable }; } -JS::NonnullGCPtr ReadableStream::pipe_to(WritableStream& destination, StreamPipeOptions const& options) +JS::NonnullGCPtr ReadableStream::pipe_to(WritableStream& destination, StreamPipeOptions const& options) { auto& realm = this->realm(); + auto& vm = realm.vm(); // 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception. if (is_readable_stream_locked(*this)) { - auto promise = WebIDL::create_promise(realm); - WebIDL::reject_promise(realm, promise, JS::TypeError::create(realm, "Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe a locked stream"sv)); - return promise->promise(); + return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion("Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe a locked stream"sv)); } // 2. If ! IsWritableStreamLocked(destination) is true, return a promise rejected with a TypeError exception. if (is_writable_stream_locked(destination)) { - auto promise = WebIDL::create_promise(realm); - WebIDL::reject_promise(realm, promise, JS::TypeError::create(realm, "Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe to a locked stream"sv)); - return promise->promise(); + return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion("Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe to a locked stream"sv)); } // 3. Let signal be options["signal"] if it exists, or undefined otherwise. auto signal = options.signal ? JS::Value(options.signal) : JS::js_undefined(); // 4. Return ! ReadableStreamPipeTo(this, destination, options["preventClose"], options["preventAbort"], options["preventCancel"], signal). - return readable_stream_pipe_to(*this, destination, options.prevent_close, options.prevent_abort, options.prevent_cancel, signal)->promise(); + return readable_stream_pipe_to(*this, destination, options.prevent_close, options.prevent_abort, options.prevent_cancel, signal); } // https://streams.spec.whatwg.org/#readablestream-tee diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStream.h b/Userland/Libraries/LibWeb/Streams/ReadableStream.h index ff9bcc0b573..621af87a3b1 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStream.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableStream.h @@ -75,10 +75,10 @@ public: virtual ~ReadableStream() override; bool locked() const; - JS::NonnullGCPtr cancel(JS::Value reason); + JS::NonnullGCPtr cancel(JS::Value reason); WebIDL::ExceptionOr get_reader(ReadableStreamGetReaderOptions const& = {}); WebIDL::ExceptionOr> pipe_through(ReadableWritablePair transform, StreamPipeOptions const& = {}); - JS::NonnullGCPtr pipe_to(WritableStream& destination, StreamPipeOptions const& = {}); + JS::NonnullGCPtr pipe_to(WritableStream& destination, StreamPipeOptions const& = {}); WebIDL::ExceptionOr tee(); void close(); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp index 3861c1f5926..8e2dc7f5a5b 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.cpp @@ -107,7 +107,7 @@ private: JS_DEFINE_ALLOCATOR(BYOBReaderReadIntoRequest); // https://streams.spec.whatwg.org/#byob-reader-read -JS::NonnullGCPtr ReadableStreamBYOBReader::read(JS::Handle& view, ReadableStreamBYOBReaderReadOptions options) +JS::NonnullGCPtr ReadableStreamBYOBReader::read(JS::Handle& view, ReadableStreamBYOBReaderReadOptions options) { auto& realm = this->realm(); @@ -177,6 +177,6 @@ JS::NonnullGCPtr ReadableStreamBYOBReader::read(JS::Handle(*promise_capability->promise()) }; + return promise_capability; } } diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.h b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.h index 264ef5437f8..0cccd7f4795 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamBYOBReader.h @@ -51,7 +51,7 @@ public: virtual ~ReadableStreamBYOBReader() override = default; - JS::NonnullGCPtr read(JS::Handle&, ReadableStreamBYOBReaderReadOptions options = {}); + JS::NonnullGCPtr read(JS::Handle&, ReadableStreamBYOBReaderReadOptions options = {}); void release_lock(); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp index cd5ff70a3fc..40e455a19f5 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp @@ -162,7 +162,7 @@ private: JS_DEFINE_ALLOCATOR(DefaultReaderReadRequest); // https://streams.spec.whatwg.org/#default-reader-read -JS::NonnullGCPtr ReadableStreamDefaultReader::read() +JS::NonnullGCPtr ReadableStreamDefaultReader::read() { auto& realm = this->realm(); @@ -188,7 +188,7 @@ JS::NonnullGCPtr ReadableStreamDefaultReader::read() readable_stream_default_reader_read(*this, read_request); // 5. Return promise. - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise()) }; + return promise_capability; } void ReadableStreamDefaultReader::read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request) diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h b/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h index 0d69271b942..ad2cdd75483 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.h @@ -77,7 +77,7 @@ public: virtual ~ReadableStreamDefaultReader() override = default; - JS::NonnullGCPtr read(); + JS::NonnullGCPtr read(); void read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request); void read_all_bytes(JS::NonnullGCPtr, JS::NonnullGCPtr); diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp index 4a75b695ff7..423293aac45 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.cpp @@ -14,14 +14,14 @@ namespace Web::Streams { // https://streams.spec.whatwg.org/#generic-reader-closed -JS::GCPtr ReadableStreamGenericReaderMixin::closed() +JS::GCPtr ReadableStreamGenericReaderMixin::closed() { // 1. Return this.[[closedPromise]]. - return JS::GCPtr { verify_cast(*m_closed_promise->promise()) }; + return m_closed_promise; } // https://streams.spec.whatwg.org/#generic-reader-cancel -JS::NonnullGCPtr ReadableStreamGenericReaderMixin::cancel(JS::Value reason) +JS::NonnullGCPtr ReadableStreamGenericReaderMixin::cancel(JS::Value reason) { // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. if (!m_stream) { @@ -30,8 +30,7 @@ JS::NonnullGCPtr ReadableStreamGenericReaderMixin::cancel(JS::Value } // 2. Return ! ReadableStreamReaderGenericCancel(this, reason). - auto promise_capability = readable_stream_reader_generic_cancel(*this, reason); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise().ptr()) }; + return readable_stream_reader_generic_cancel(*this, reason); } ReadableStreamGenericReaderMixin::ReadableStreamGenericReaderMixin(JS::Realm& realm) diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.h b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.h index 6b8579e5cd5..e59732ebb99 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.h +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamGenericReader.h @@ -19,9 +19,9 @@ class ReadableStreamGenericReaderMixin { public: virtual ~ReadableStreamGenericReaderMixin() = default; - JS::GCPtr closed(); + JS::GCPtr closed(); - JS::NonnullGCPtr cancel(JS::Value reason); + JS::NonnullGCPtr cancel(JS::Value reason); JS::GCPtr stream() const { return m_stream; } void set_stream(JS::GCPtr stream) { m_stream = stream; } diff --git a/Userland/Libraries/LibWeb/Streams/WritableStream.cpp b/Userland/Libraries/LibWeb/Streams/WritableStream.cpp index 0a500380cf2..060a42e40d5 100644 --- a/Userland/Libraries/LibWeb/Streams/WritableStream.cpp +++ b/Userland/Libraries/LibWeb/Streams/WritableStream.cpp @@ -58,39 +58,39 @@ bool WritableStream::locked() const } // https://streams.spec.whatwg.org/#ws-close -JS::GCPtr WritableStream::close() +JS::GCPtr WritableStream::close() { auto& realm = this->realm(); // 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception. if (is_writable_stream_locked(*this)) { auto exception = JS::TypeError::create(realm, "Cannot close a locked stream"sv); - return WebIDL::create_rejected_promise(realm, exception)->promise(); + return WebIDL::create_rejected_promise(realm, exception); } // 2. If ! WritableStreamCloseQueuedOrInFlight(this) is true, return a promise rejected with a TypeError exception. if (writable_stream_close_queued_or_in_flight(*this)) { auto exception = JS::TypeError::create(realm, "Cannot close a stream that is already closed or errored"sv); - return WebIDL::create_rejected_promise(realm, exception)->promise(); + return WebIDL::create_rejected_promise(realm, exception); } // 3. Return ! WritableStreamClose(this). - return writable_stream_close(*this)->promise(); + return writable_stream_close(*this); } // https://streams.spec.whatwg.org/#ws-abort -JS::GCPtr WritableStream::abort(JS::Value reason) +JS::GCPtr WritableStream::abort(JS::Value reason) { auto& realm = this->realm(); // 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception. if (is_writable_stream_locked(*this)) { auto exception = JS::TypeError::create(realm, "Cannot abort a locked stream"sv); - return WebIDL::create_rejected_promise(realm, exception)->promise(); + return WebIDL::create_rejected_promise(realm, exception); } // 2. Return ! WritableStreamAbort(this, reason). - return writable_stream_abort(*this, reason)->promise(); + return writable_stream_abort(*this, reason); } // https://streams.spec.whatwg.org/#ws-get-writer diff --git a/Userland/Libraries/LibWeb/Streams/WritableStream.h b/Userland/Libraries/LibWeb/Streams/WritableStream.h index 933824c46f8..43f416f10ad 100644 --- a/Userland/Libraries/LibWeb/Streams/WritableStream.h +++ b/Userland/Libraries/LibWeb/Streams/WritableStream.h @@ -49,8 +49,8 @@ public: virtual ~WritableStream() = default; bool locked() const; - JS::GCPtr abort(JS::Value reason); - JS::GCPtr close(); + JS::GCPtr abort(JS::Value reason); + JS::GCPtr close(); WebIDL::ExceptionOr> get_writer(); bool backpressure() const { return m_backpressure; } diff --git a/Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.cpp b/Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.cpp index 04b87a8a9ec..07e55c712f6 100644 --- a/Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.cpp +++ b/Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.cpp @@ -27,10 +27,10 @@ WebIDL::ExceptionOr> WritableStrea } // https://streams.spec.whatwg.org/#default-writer-closed -JS::GCPtr WritableStreamDefaultWriter::closed() +JS::GCPtr WritableStreamDefaultWriter::closed() { // 1. Return this.[[closedPromise]]. - return m_closed_promise->promise(); + return m_closed_promise; } // https://streams.spec.whatwg.org/#default-writer-desired-size @@ -45,29 +45,29 @@ WebIDL::ExceptionOr> WritableStreamDefaultWriter::desired_size( } // https://streams.spec.whatwg.org/#default-writer-ready -JS::GCPtr WritableStreamDefaultWriter::ready() +JS::GCPtr WritableStreamDefaultWriter::ready() { // 1. Return this.[[readyPromise]]. - return m_ready_promise->promise(); + return m_ready_promise; } // https://streams.spec.whatwg.org/#default-writer-abort -JS::GCPtr WritableStreamDefaultWriter::abort(JS::Value reason) +JS::GCPtr WritableStreamDefaultWriter::abort(JS::Value reason) { auto& realm = this->realm(); // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. if (!m_stream) { auto exception = JS::TypeError::create(realm, "Cannot abort a writer that has no locked stream"sv); - return WebIDL::create_rejected_promise(realm, exception)->promise(); + return WebIDL::create_rejected_promise(realm, exception); } // 2. Return ! WritableStreamDefaultWriterAbort(this, reason). - return writable_stream_default_writer_abort(*this, reason)->promise(); + return writable_stream_default_writer_abort(*this, reason); } // https://streams.spec.whatwg.org/#default-writer-close -JS::GCPtr WritableStreamDefaultWriter::close() +JS::GCPtr WritableStreamDefaultWriter::close() { auto& realm = this->realm(); @@ -76,17 +76,17 @@ JS::GCPtr WritableStreamDefaultWriter::close() // 2. If stream is undefined, return a promise rejected with a TypeError exception. if (!m_stream) { auto exception = JS::TypeError::create(realm, "Cannot close a writer that has no locked stream"sv); - return WebIDL::create_rejected_promise(realm, exception)->promise(); + return WebIDL::create_rejected_promise(realm, exception); } // 3. If ! WritableStreamCloseQueuedOrInFlight(stream) is true, return a promise rejected with a TypeError exception. if (writable_stream_close_queued_or_in_flight(*m_stream)) { auto exception = JS::TypeError::create(realm, "Cannot close a stream that is already closed or errored"sv); - return WebIDL::create_rejected_promise(realm, exception)->promise(); + return WebIDL::create_rejected_promise(realm, exception); } // 4. Return ! WritableStreamDefaultWriterClose(this). - return writable_stream_default_writer_close(*this)->promise(); + return writable_stream_default_writer_close(*this); } // https://streams.spec.whatwg.org/#default-writer-release-lock @@ -106,18 +106,18 @@ void WritableStreamDefaultWriter::release_lock() } // https://streams.spec.whatwg.org/#default-writer-write -JS::GCPtr WritableStreamDefaultWriter::write(JS::Value chunk) +JS::GCPtr WritableStreamDefaultWriter::write(JS::Value chunk) { auto& realm = this->realm(); // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. if (!m_stream) { auto exception = JS::TypeError::create(realm, "Cannot write to a writer that has no locked stream"sv); - return WebIDL::create_rejected_promise(realm, exception)->promise(); + return WebIDL::create_rejected_promise(realm, exception); } // 2. Return ! WritableStreamDefaultWriterWrite(this, chunk). - return writable_stream_default_writer_write(*this, chunk)->promise(); + return writable_stream_default_writer_write(*this, chunk); } WritableStreamDefaultWriter::WritableStreamDefaultWriter(JS::Realm& realm) diff --git a/Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.h b/Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.h index 4b85f4e301c..1f06f257ac3 100644 --- a/Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.h +++ b/Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.h @@ -25,13 +25,13 @@ public: virtual ~WritableStreamDefaultWriter() override = default; - JS::GCPtr closed(); + JS::GCPtr closed(); WebIDL::ExceptionOr> desired_size() const; - JS::GCPtr ready(); - JS::GCPtr abort(JS::Value reason); - JS::GCPtr close(); + JS::GCPtr ready(); + JS::GCPtr abort(JS::Value reason); + JS::GCPtr close(); void release_lock(); - JS::GCPtr write(JS::Value chunk); + JS::GCPtr write(JS::Value chunk); JS::GCPtr closed_promise() { return m_closed_promise; } void set_closed_promise(JS::GCPtr value) { m_closed_promise = value; } diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index 53062c5ab50..7e9047ec14e 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -19,12 +19,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include namespace Web::WebAssembly { @@ -80,26 +82,25 @@ bool validate(JS::VM& vm, JS::Handle& bytes) } // https://webassembly.github.io/spec/js-api/#dom-webassembly-compile -WebIDL::ExceptionOr compile(JS::VM& vm, JS::Handle& bytes) +WebIDL::ExceptionOr> compile(JS::VM& vm, JS::Handle& bytes) { auto& realm = *vm.current_realm(); // FIXME: This shouldn't block! auto compiled_module_or_error = Detail::parse_module(vm, bytes->raw_object()); - auto promise = JS::Promise::create(realm); - + auto promise = WebIDL::create_promise(realm); if (compiled_module_or_error.is_error()) { - promise->reject(*compiled_module_or_error.release_error().value()); + WebIDL::reject_promise(realm, promise, compiled_module_or_error.error_value()); } else { auto module_object = vm.heap().allocate(realm, realm, compiled_module_or_error.release_value()); - promise->fulfill(module_object); + WebIDL::resolve_promise(realm, promise, module_object); } return promise; } // https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate -WebIDL::ExceptionOr instantiate(JS::VM& vm, JS::Handle& bytes, Optional>& import_object) +WebIDL::ExceptionOr> instantiate(JS::VM& vm, JS::Handle& bytes, Optional>& import_object) { // FIXME: Implement the importObject parameter. (void)import_object; @@ -108,10 +109,10 @@ WebIDL::ExceptionOr instantiate(JS::VM& vm, JS::Handleraw_object()); - auto promise = JS::Promise::create(realm); + auto promise = WebIDL::create_promise(realm); if (compiled_module_or_error.is_error()) { - promise->reject(*compiled_module_or_error.release_error().value()); + WebIDL::reject_promise(realm, promise, compiled_module_or_error.error_value()); return promise; } @@ -119,7 +120,7 @@ WebIDL::ExceptionOr instantiate(JS::VM& vm, JS::Handlemodule); if (result.is_error()) { - promise->reject(*result.release_error().value()); + WebIDL::reject_promise(realm, promise, result.error_value()); } else { auto module_object = vm.heap().allocate(realm, realm, move(compiled_module)); auto instance_object = vm.heap().allocate(realm, realm, result.release_value()); @@ -127,29 +128,30 @@ WebIDL::ExceptionOr instantiate(JS::VM& vm, JS::Handledefine_direct_property("module", module_object, JS::default_attributes); object->define_direct_property("instance", instance_object, JS::default_attributes); - promise->fulfill(object); + WebIDL::resolve_promise(realm, promise, object); } return promise; } // https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate-moduleobject-importobject -WebIDL::ExceptionOr instantiate(JS::VM& vm, Module const& module_object, Optional>& import_object) +WebIDL::ExceptionOr> instantiate(JS::VM& vm, Module const& module_object, Optional>& import_object) { // FIXME: Implement the importObject parameter. (void)import_object; auto& realm = *vm.current_realm(); - auto promise = JS::Promise::create(realm); + auto promise = WebIDL::create_promise(realm); + // FIXME: This shouldn't block! auto const& compiled_module = module_object.compiled_module(); auto result = Detail::instantiate_module(vm, compiled_module->module); if (result.is_error()) { - promise->reject(*result.release_error().value()); + WebIDL::reject_promise(realm, promise, result.error_value()); } else { auto instance_object = vm.heap().allocate(realm, realm, result.release_value()); - promise->fulfill(instance_object); + WebIDL::resolve_promise(realm, promise, instance_object); } return promise; diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h index 19397b50164..9d92baa5cc3 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.h @@ -22,10 +22,10 @@ void visit_edges(JS::Object&, JS::Cell::Visitor&); void finalize(JS::Object&); bool validate(JS::VM&, JS::Handle& bytes); -WebIDL::ExceptionOr compile(JS::VM&, JS::Handle& bytes); +WebIDL::ExceptionOr> compile(JS::VM&, JS::Handle& bytes); -WebIDL::ExceptionOr instantiate(JS::VM&, JS::Handle& bytes, Optional>& import_object); -WebIDL::ExceptionOr instantiate(JS::VM&, Module const& module_object, Optional>& import_object); +WebIDL::ExceptionOr> instantiate(JS::VM&, JS::Handle& bytes, Optional>& import_object); +WebIDL::ExceptionOr> instantiate(JS::VM&, Module const& module_object, Optional>& import_object); namespace Detail { struct CompiledWebAssemblyModule : public RefCounted { diff --git a/Userland/Libraries/LibWeb/WebAudio/AudioContext.cpp b/Userland/Libraries/LibWeb/WebAudio/AudioContext.cpp index 531d05efb1b..0e182eeb2f4 100644 --- a/Userland/Libraries/LibWeb/WebAudio/AudioContext.cpp +++ b/Userland/Libraries/LibWeb/WebAudio/AudioContext.cpp @@ -103,7 +103,7 @@ AudioTimestamp AudioContext::get_output_timestamp() } // https://www.w3.org/TR/webaudio/#dom-audiocontext-resume -WebIDL::ExceptionOr> AudioContext::resume() +WebIDL::ExceptionOr> AudioContext::resume() { auto& realm = this->realm(); @@ -118,7 +118,7 @@ WebIDL::ExceptionOr> AudioContext::resume() // 3. If the [[control thread state]] on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise. if (state() == Bindings::AudioContextState::Closed) { WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string)); - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } // 4. Set [[suspended by user]] to true. @@ -187,11 +187,11 @@ WebIDL::ExceptionOr> AudioContext::resume() })); // 8. Return promise. - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } // https://www.w3.org/TR/webaudio/#dom-audiocontext-suspend -WebIDL::ExceptionOr> AudioContext::suspend() +WebIDL::ExceptionOr> AudioContext::suspend() { auto& realm = this->realm(); @@ -206,7 +206,7 @@ WebIDL::ExceptionOr> AudioContext::suspend() // 3. If the [[control thread state]] on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise. if (state() == Bindings::AudioContextState::Closed) { WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string)); - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } // 4. Append promise to [[pending promises]]. @@ -244,11 +244,11 @@ WebIDL::ExceptionOr> AudioContext::suspend() })); // 8. Return promise. - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } // https://www.w3.org/TR/webaudio/#dom-audiocontext-close -WebIDL::ExceptionOr> AudioContext::close() +WebIDL::ExceptionOr> AudioContext::close() { auto& realm = this->realm(); @@ -263,7 +263,7 @@ WebIDL::ExceptionOr> AudioContext::close() // 3. If the [[control thread state]] flag on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise. if (state() == Bindings::AudioContextState::Closed) { WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string)); - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } // 4. Set the [[control thread state]] flag on the AudioContext to closed. @@ -296,7 +296,7 @@ WebIDL::ExceptionOr> AudioContext::close() })); // 6. Return promise - return JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + return promise; } // FIXME: Actually implement the rendering thread diff --git a/Userland/Libraries/LibWeb/WebAudio/AudioContext.h b/Userland/Libraries/LibWeb/WebAudio/AudioContext.h index daad254029c..9c67c3656bb 100644 --- a/Userland/Libraries/LibWeb/WebAudio/AudioContext.h +++ b/Userland/Libraries/LibWeb/WebAudio/AudioContext.h @@ -35,9 +35,9 @@ public: double base_latency() const { return m_base_latency; } double output_latency() const { return m_output_latency; } AudioTimestamp get_output_timestamp(); - WebIDL::ExceptionOr> resume(); - WebIDL::ExceptionOr> suspend(); - WebIDL::ExceptionOr> close(); + WebIDL::ExceptionOr> resume(); + WebIDL::ExceptionOr> suspend(); + WebIDL::ExceptionOr> close(); private: explicit AudioContext(JS::Realm&, AudioContextOptions const& context_options); diff --git a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp index ddd6451573a..587791596cb 100644 --- a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp +++ b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp @@ -128,7 +128,7 @@ void BaseAudioContext::queue_a_media_element_task(JS::NonnullGCPtr BaseAudioContext::decode_audio_data(JS::Handle audio_data, JS::GCPtr success_callback, JS::GCPtr error_callback) +JS::NonnullGCPtr BaseAudioContext::decode_audio_data(JS::Handle audio_data, JS::GCPtr success_callback, JS::GCPtr error_callback) { auto& realm = this->realm(); @@ -178,7 +178,7 @@ JS::NonnullGCPtr BaseAudioContext::decode_audio_data(JS::Handle(*promise->promise()); + return promise; } // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-decodeaudiodata diff --git a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.h b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.h index 27b10eb9cf5..597435e81bf 100644 --- a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.h +++ b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.h @@ -61,7 +61,7 @@ public: WebIDL::ExceptionOr> create_dynamics_compressor(); JS::NonnullGCPtr create_gain(); - JS::NonnullGCPtr decode_audio_data(JS::Handle, JS::GCPtr, JS::GCPtr); + JS::NonnullGCPtr decode_audio_data(JS::Handle, JS::GCPtr, JS::GCPtr); protected: explicit BaseAudioContext(JS::Realm&, float m_sample_rate = 0); diff --git a/Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.cpp b/Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.cpp index 26a2cca27db..9b1f4f120c2 100644 --- a/Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.cpp +++ b/Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.cpp @@ -32,17 +32,17 @@ WebIDL::ExceptionOr> OfflineAudioContext:: OfflineAudioContext::~OfflineAudioContext() = default; // https://webaudio.github.io/web-audio-api/#dom-offlineaudiocontext-startrendering -WebIDL::ExceptionOr> OfflineAudioContext::start_rendering() +WebIDL::ExceptionOr> OfflineAudioContext::start_rendering() { return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::start_rendering"_string); } -WebIDL::ExceptionOr> OfflineAudioContext::resume() +WebIDL::ExceptionOr> OfflineAudioContext::resume() { return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::resume"_string); } -WebIDL::ExceptionOr> OfflineAudioContext::suspend(double suspend_time) +WebIDL::ExceptionOr> OfflineAudioContext::suspend(double suspend_time) { (void)suspend_time; return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::suspend"_string); diff --git a/Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.h b/Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.h index a9c70c9dca8..00e4c3842fa 100644 --- a/Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.h +++ b/Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.h @@ -32,9 +32,9 @@ public: virtual ~OfflineAudioContext() override; - WebIDL::ExceptionOr> start_rendering(); - WebIDL::ExceptionOr> resume(); - WebIDL::ExceptionOr> suspend(double suspend_time); + WebIDL::ExceptionOr> start_rendering(); + WebIDL::ExceptionOr> resume(); + WebIDL::ExceptionOr> suspend(double suspend_time); WebIDL::UnsignedLong length() const; diff --git a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp index f1433d361fd..00d17cda6e8 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp @@ -376,24 +376,24 @@ void execute_script(HTML::BrowsingContext const& browsing_context, ByteString bo HTML::TemporaryExecutionContext execution_context { document->relevant_settings_object(), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; // 7. Let promise be a new Promise. - auto promise_capability = WebIDL::create_promise(realm); - JS::NonnullGCPtr promise { verify_cast(*promise_capability->promise()) }; + auto promise = WebIDL::create_promise(realm); // 8. Run the following substeps in parallel: - Platform::EventLoopPlugin::the().deferred_invoke([&realm, &browsing_context, promise_capability, document, promise, body = move(body), arguments = move(arguments)]() mutable { + Platform::EventLoopPlugin::the().deferred_invoke([&realm, &browsing_context, promise, document, body = move(body), arguments = move(arguments)]() mutable { HTML::TemporaryExecutionContext execution_context { document->relevant_settings_object() }; // 1. Let scriptPromise be the result of promise-calling execute a function body, with arguments body and arguments. auto script_result = execute_a_function_body(browsing_context, body, move(arguments)); + // FIXME: This isn't right, we should be reacting to this using WebIDL::react_to_promise() // 2. Upon fulfillment of scriptPromise with value v, resolve promise with value v. if (script_result.has_value()) { - WebIDL::resolve_promise(realm, promise_capability, script_result.release_value()); + WebIDL::resolve_promise(realm, promise, script_result.release_value()); } // 3. Upon rejection of scriptPromise with value r, reject promise with value r. if (script_result.is_throw_completion()) { - promise->reject(*script_result.throw_completion().value()); + WebIDL::reject_promise(realm, promise, *script_result.throw_completion().value()); } }); @@ -403,7 +403,9 @@ void execute_script(HTML::BrowsingContext const& browsing_context, ByteString bo return JS::js_undefined(); timer->stop(); - auto json_value_or_error = json_clone(realm, browsing_context, promise->result()); + auto promise_promise = JS::NonnullGCPtr { verify_cast(*promise->promise()) }; + + auto json_value_or_error = json_clone(realm, browsing_context, promise_promise->result()); if (json_value_or_error.is_error()) { auto error_object = JsonObject {}; error_object.set("name", "Error"); @@ -416,19 +418,19 @@ void execute_script(HTML::BrowsingContext const& browsing_context, ByteString bo // NOTE: This is handled by the HeapTimer. // 11. If promise is fulfilled with value v, let result be JSON clone with session and v, and return success with data result. - else if (promise->state() == JS::Promise::State::Fulfilled) { + else if (promise_promise->state() == JS::Promise::State::Fulfilled) { on_complete->function()({ ExecuteScriptResultType::PromiseResolved, json_value_or_error.release_value() }); } // 12. If promise is rejected with reason r, let result be JSON clone with session and r, and return error with error code javascript error and data result. - else if (promise->state() == JS::Promise::State::Rejected) { + else if (promise_promise->state() == JS::Promise::State::Rejected) { on_complete->function()({ ExecuteScriptResultType::PromiseRejected, json_value_or_error.release_value() }); } return JS::js_undefined(); }); - WebIDL::react_to_promise(promise_capability, reaction_steps, reaction_steps); + WebIDL::react_to_promise(promise, reaction_steps, reaction_steps); } void execute_async_script(HTML::BrowsingContext const& browsing_context, ByteString body, JS::MarkedVector arguments, Optional const& timeout_ms, JS::NonnullGCPtr on_complete) diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp index f2dd79d3d99..25de081d205 100644 --- a/Userland/Libraries/LibWeb/WebIDL/Promise.cpp +++ b/Userland/Libraries/LibWeb/WebIDL/Promise.cpp @@ -93,7 +93,7 @@ void reject_promise(JS::Realm& realm, Promise const& promise, JS::Value reason) } // https://webidl.spec.whatwg.org/#dfn-perform-steps-once-promise-is-settled -JS::NonnullGCPtr react_to_promise(Promise const& promise, JS::GCPtr on_fulfilled_callback, JS::GCPtr on_rejected_callback) +JS::NonnullGCPtr react_to_promise(Promise const& promise, JS::GCPtr on_fulfilled_callback, JS::GCPtr on_rejected_callback) { auto& realm = promise.promise()->shape().realm(); auto& vm = realm.vm(); @@ -140,13 +140,17 @@ JS::NonnullGCPtr react_to_promise(Promise const& promise, JS::GCPtr auto new_capability = MUST(JS::new_promise_capability(vm, constructor)); // 7. Return PerformPromiseThen(promise.[[Promise]], onFulfilled, onRejected, newCapability). + // FIXME: https://github.com/whatwg/webidl/issues/1443 + // Returning newCapability instead of newCapability.[[Promise]. auto promise_object = verify_cast(promise.promise().ptr()); auto value = promise_object->perform_then(on_fulfilled, on_rejected, new_capability); - return verify_cast(value.as_object()); + + VERIFY(value == new_capability->promise()); + return new_capability; } // https://webidl.spec.whatwg.org/#upon-fulfillment -JS::NonnullGCPtr upon_fulfillment(Promise const& promise, JS::NonnullGCPtr steps) +JS::NonnullGCPtr upon_fulfillment(Promise const& promise, JS::NonnullGCPtr steps) { // 1. Return the result of reacting to promise: return react_to_promise(promise, @@ -157,7 +161,7 @@ JS::NonnullGCPtr upon_fulfillment(Promise const& promise, JS::Nonnu } // https://webidl.spec.whatwg.org/#upon-rejection -JS::NonnullGCPtr upon_rejection(Promise const& promise, JS::NonnullGCPtr steps) +JS::NonnullGCPtr upon_rejection(Promise const& promise, JS::NonnullGCPtr steps) { // 1. Return the result of reacting to promise: return react_to_promise(promise, {}, @@ -287,11 +291,10 @@ void wait_for_all(JS::Realm& realm, Vector> const& pro } } -JS::NonnullGCPtr create_rejected_promise_from_exception(JS::Realm& realm, Exception exception) +JS::NonnullGCPtr create_rejected_promise_from_exception(JS::Realm& realm, Exception exception) { auto throw_completion = Bindings::dom_exception_to_throw_completion(realm.vm(), move(exception)); - auto promise_capability = WebIDL::create_rejected_promise(realm, *throw_completion.value()); - return JS::NonnullGCPtr { verify_cast(*promise_capability->promise().ptr()) }; + return WebIDL::create_rejected_promise(realm, *throw_completion.value()); } } diff --git a/Userland/Libraries/LibWeb/WebIDL/Promise.h b/Userland/Libraries/LibWeb/WebIDL/Promise.h index a2d91c268a1..08cdec13b9f 100644 --- a/Userland/Libraries/LibWeb/WebIDL/Promise.h +++ b/Userland/Libraries/LibWeb/WebIDL/Promise.h @@ -27,13 +27,13 @@ JS::NonnullGCPtr create_resolved_promise(JS::Realm&, JS::Value); JS::NonnullGCPtr create_rejected_promise(JS::Realm&, JS::Value); void resolve_promise(JS::Realm&, Promise const&, JS::Value = JS::js_undefined()); void reject_promise(JS::Realm&, Promise const&, JS::Value); -JS::NonnullGCPtr react_to_promise(Promise const&, JS::GCPtr on_fulfilled_callback, JS::GCPtr on_rejected_callback); -JS::NonnullGCPtr upon_fulfillment(Promise const&, JS::NonnullGCPtr); -JS::NonnullGCPtr upon_rejection(Promise const&, JS::NonnullGCPtr); +JS::NonnullGCPtr react_to_promise(Promise const&, JS::GCPtr on_fulfilled_callback, JS::GCPtr on_rejected_callback); +JS::NonnullGCPtr upon_fulfillment(Promise const&, JS::NonnullGCPtr); +JS::NonnullGCPtr upon_rejection(Promise const&, JS::NonnullGCPtr); void mark_promise_as_handled(Promise const&); void wait_for_all(JS::Realm&, Vector> const& promises, Function const&)> success_steps, Function failure_steps); // Non-spec, convenience method. -JS::NonnullGCPtr create_rejected_promise_from_exception(JS::Realm&, Exception); +JS::NonnullGCPtr create_rejected_promise_from_exception(JS::Realm&, Exception); }