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<T>` 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.
This commit is contained in:
Andrew Kaster 2024-10-25 12:38:19 -06:00 committed by Andrew Kaster
commit 2c3531ab78
Notes: github-actions[bot] 2024-10-25 20:05:22 +00:00
61 changed files with 323 additions and 306 deletions

View file

@ -665,16 +665,17 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
} }
} }
} else if (parameter.type->name() == "Promise") { } else if (parameter.type->name() == "Promise") {
// NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved // https://webidl.spec.whatwg.org/#js-promise
// 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.
scoped_generator.append(R"~~~( scoped_generator.append(R"~~~(
if (!@js_name@@js_suffix@.is_object() || !is<JS::Promise>(@js_name@@js_suffix@.as_object())) { if (!@js_name@@js_suffix@.is_cell() || !is<JS::PromiseCapability>(@js_name@@js_suffix@.as_cell())) {
auto new_promise = JS::Promise::create(realm); // 1. Let promiseCapability be ? NewPromiseCapability(%Promise%).
new_promise->fulfill(@js_name@@js_suffix@); auto promise_capability = TRY(JS::new_promise_capability(vm, realm.intrinsics().promise_constructor()));
@js_name@@js_suffix@ = new_promise; // 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::Promise&>(@js_name@@js_suffix@.as_object())); auto @cpp_name@ = JS::make_handle(static_cast<JS::PromiseCapability&>(@js_name@@js_suffix@.as_cell()));
)~~~"); )~~~");
} else if (parameter.type->name() == "object") { } else if (parameter.type->name() == "object") {
if (parameter.type->is_nullable()) { if (parameter.type->is_nullable()) {
@ -1794,9 +1795,13 @@ static void generate_wrap_statement(SourceGenerator& generator, ByteString const
} }
} else if (type.is_integer()) { } else if (type.is_integer()) {
generate_from_integral(scoped_generator, type); 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"~~~( scoped_generator.append(R"~~~(
@result_expression@ @value@; @result_expression@ @value@;
)~~~");
} else if (type.name() == "Promise") {
scoped_generator.append(R"~~~(
@result_expression@ JS::NonnullGCPtr { verify_cast<JS::Promise>(*@value@->promise()) };
)~~~"); )~~~");
} else if (type.name() == "ArrayBufferView" || type.name() == "BufferSource") { } else if (type.name() == "ArrayBufferView" || type.name() == "BufferSource") {
scoped_generator.append(R"~~~( scoped_generator.append(R"~~~(
@ -4243,6 +4248,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu
#include <LibJS/Runtime/DataView.h> #include <LibJS/Runtime/DataView.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/PrimitiveString.h> #include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/TypedArray.h> #include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h> #include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h> #include <LibJS/Runtime/ValueInlines.h>
@ -4254,6 +4260,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu
#include <LibWeb/WebIDL/AbstractOperations.h> #include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h> #include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/OverloadResolution.h> #include <LibWeb/WebIDL/OverloadResolution.h>
#include <LibWeb/WebIDL/Promise.h>
#include <LibWeb/WebIDL/Tracing.h> #include <LibWeb/WebIDL/Tracing.h>
#include <LibWeb/WebIDL/Types.h> #include <LibWeb/WebIDL/Types.h>
@ -4663,6 +4670,7 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu
#include <LibJS/Runtime/FunctionObject.h> #include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Iterator.h> #include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/TypedArray.h> #include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h> #include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h> #include <LibJS/Runtime/ValueInlines.h>
@ -4682,8 +4690,9 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu
#include <LibWeb/Infra/Strings.h> #include <LibWeb/Infra/Strings.h>
#include <LibWeb/WebIDL/AbstractOperations.h> #include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h> #include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/Tracing.h>
#include <LibWeb/WebIDL/OverloadResolution.h> #include <LibWeb/WebIDL/OverloadResolution.h>
#include <LibWeb/WebIDL/Promise.h>
#include <LibWeb/WebIDL/Tracing.h>
#include <LibWeb/WebIDL/Types.h> #include <LibWeb/WebIDL/Types.h>
#if __has_include(<LibWeb/Bindings/@prototype_base_class@.h>) #if __has_include(<LibWeb/Bindings/@prototype_base_class@.h>)

View file

@ -60,10 +60,10 @@ public:
bool pending() const { return m_pending_play_task == TaskState::Scheduled || m_pending_pause_task == TaskState::Scheduled; } 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 // https://www.w3.org/TR/web-animations-1/#dom-animation-ready
JS::NonnullGCPtr<JS::Object> ready() const { return *current_ready_promise()->promise(); } JS::NonnullGCPtr<WebIDL::Promise> ready() const { return current_ready_promise(); }
// https://www.w3.org/TR/web-animations-1/#dom-animation-finished // https://www.w3.org/TR/web-animations-1/#dom-animation-finished
JS::NonnullGCPtr<JS::Object> finished() const { return *current_finished_promise()->promise(); } JS::NonnullGCPtr<WebIDL::Promise> finished() const { return current_finished_promise(); }
bool is_finished() const { return m_is_finished; } bool is_finished() const { return m_is_finished; }
JS::GCPtr<WebIDL::CallbackType> onfinish(); JS::GCPtr<WebIDL::CallbackType> onfinish();

View file

@ -14,6 +14,7 @@
#include <LibWeb/CSS/StyleComputer.h> #include <LibWeb/CSS/StyleComputer.h>
#include <LibWeb/CSS/StyleSheetList.h> #include <LibWeb/CSS/StyleSheetList.h>
#include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/HTML/Window.h> #include <LibWeb/HTML/Window.h>
#include <LibWeb/Platform/EventLoopPlugin.h> #include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/WebIDL/ExceptionOr.h> #include <LibWeb/WebIDL/ExceptionOr.h>
@ -186,19 +187,21 @@ WebIDL::ExceptionOr<void> CSSStyleSheet::delete_rule(unsigned index)
} }
// https://drafts.csswg.org/cssom/#dom-cssstylesheet-replace // https://drafts.csswg.org/cssom/#dom-cssstylesheet-replace
JS::NonnullGCPtr<JS::Promise> CSSStyleSheet::replace(String text) JS::NonnullGCPtr<WebIDL::Promise> CSSStyleSheet::replace(String text)
{ {
auto& realm = this->realm();
// 1. Let promise be a promise // 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. // 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()) { 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; return promise;
} }
if (disallow_modification()) { 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; return promise;
} }
@ -206,14 +209,16 @@ JS::NonnullGCPtr<JS::Promise> CSSStyleSheet::replace(String text)
set_disallow_modification(true); set_disallow_modification(true);
// 4. In parallel, do these steps: // 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 stylesheets contents from text. // 1. Let rules be the result of running parse a stylesheets 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* parsed_stylesheet = parse_css_stylesheet(context, text);
auto& rules = parsed_stylesheet->rules(); auto& rules = parsed_stylesheet->rules();
// 2. If rules contains one or more @import rules, remove those rules from rules. // 2. If rules contains one or more @import rules, remove those rules from rules.
JS::MarkedVector<JS::NonnullGCPtr<CSSRule>> rules_without_import(realm().heap()); JS::MarkedVector<JS::NonnullGCPtr<CSSRule>> rules_without_import(realm.heap());
for (auto rule : rules) { for (auto rule : rules) {
if (rule->type() != CSSRule::Type::Import) if (rule->type() != CSSRule::Type::Import)
rules_without_import.append(rule); rules_without_import.append(rule);
@ -226,7 +231,7 @@ JS::NonnullGCPtr<JS::Promise> CSSStyleSheet::replace(String text)
set_disallow_modification(false); set_disallow_modification(false);
// 5. Resolve promise with sheet. // 5. Resolve promise with sheet.
promise->fulfill(this); WebIDL::resolve_promise(realm, *promise, this);
}); });
return promise; return promise;

View file

@ -53,7 +53,7 @@ public:
WebIDL::ExceptionOr<void> remove_rule(Optional<WebIDL::UnsignedLong> index); WebIDL::ExceptionOr<void> remove_rule(Optional<WebIDL::UnsignedLong> index);
WebIDL::ExceptionOr<void> delete_rule(unsigned index); WebIDL::ExceptionOr<void> delete_rule(unsigned index);
JS::NonnullGCPtr<JS::Promise> replace(String text); JS::NonnullGCPtr<WebIDL::Promise> replace(String text);
WebIDL::ExceptionOr<void> replace_sync(StringView text); WebIDL::ExceptionOr<void> replace_sync(StringView text);
void for_each_effective_rule(TraversalOrder, Function<void(CSSRule const&)> const& callback) const; void for_each_effective_rule(TraversalOrder, Function<void(CSSRule const&)> const& callback) const;

View file

@ -205,9 +205,9 @@ void FontFace::visit_edges(JS::Cell::Visitor& visitor)
visitor.visit(m_font_status_promise); visitor.visit(m_font_status_promise);
} }
JS::NonnullGCPtr<JS::Promise> FontFace::loaded() const JS::NonnullGCPtr<WebIDL::Promise> FontFace::loaded() const
{ {
return verify_cast<JS::Promise>(*m_font_status_promise->promise()); return m_font_status_promise;
} }
// https://drafts.csswg.org/css-font-loading/#dom-fontface-family // https://drafts.csswg.org/css-font-loading/#dom-fontface-family
@ -320,7 +320,7 @@ WebIDL::ExceptionOr<void> FontFace::set_line_gap_override(String const&)
} }
// https://drafts.csswg.org/css-font-loading/#dom-fontface-load // https://drafts.csswg.org/css-font-loading/#dom-fontface-load
JS::NonnullGCPtr<JS::Promise> FontFace::load() JS::NonnullGCPtr<WebIDL::Promise> FontFace::load()
{ {
// 1. Let font face be the FontFace object on which this method was called. // 1. Let font face be the FontFace object on which this method was called.
auto& font_face = *this; auto& font_face = *this;

View file

@ -74,8 +74,8 @@ public:
Bindings::FontFaceLoadStatus status() const { return m_status; } Bindings::FontFaceLoadStatus status() const { return m_status; }
JS::NonnullGCPtr<JS::Promise> load(); JS::NonnullGCPtr<WebIDL::Promise> load();
JS::NonnullGCPtr<JS::Promise> loaded() const; JS::NonnullGCPtr<WebIDL::Promise> loaded() const;
void load_font_source(); void load_font_source();

View file

@ -227,7 +227,7 @@ static WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Set>> find_matching_font_faces(J
} }
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-load // https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-load
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> FontFaceSet::load(String const& font, String const& text) JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> FontFaceSet::load(String const& font, String const& text)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -278,18 +278,18 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> FontFaceSet::load(String co
}); });
// 2. Return promise. Complete the rest of these steps asynchronously. // 2. Return promise. Complete the rest of these steps asynchronously.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
// https://drafts.csswg.org/css-font-loading/#font-face-set-ready // https://drafts.csswg.org/css-font-loading/#font-face-set-ready
JS::NonnullGCPtr<JS::Promise> FontFaceSet::ready() const JS::NonnullGCPtr<WebIDL::Promise> FontFaceSet::ready() const
{ {
return verify_cast<JS::Promise>(*m_ready_promise->promise()); return m_ready_promise;
} }
void FontFaceSet::resolve_ready_promise() void FontFaceSet::resolve_ready_promise()
{ {
WebIDL::resolve_promise(realm(), *m_ready_promise); WebIDL::resolve_promise(realm(), m_ready_promise);
} }
} }

View file

@ -38,9 +38,9 @@ public:
void set_onloadingerror(WebIDL::CallbackType*); void set_onloadingerror(WebIDL::CallbackType*);
WebIDL::CallbackType* onloadingerror(); WebIDL::CallbackType* onloadingerror();
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> load(String const& font, String const& text); JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> load(String const& font, String const& text);
JS::NonnullGCPtr<JS::Promise> ready() const; JS::NonnullGCPtr<WebIDL::Promise> ready() const;
Bindings::FontFaceSetLoadStatus status() const { return m_status; } Bindings::FontFaceSetLoadStatus status() const { return m_status; }
void resolve_ready_promise(); void resolve_ready_promise();
@ -52,7 +52,7 @@ private:
virtual void visit_edges(Cell::Visitor&) override; virtual void visit_edges(Cell::Visitor&) override;
JS::NonnullGCPtr<JS::Set> m_set_entries; JS::NonnullGCPtr<JS::Set> m_set_entries;
JS::GCPtr<WebIDL::Promise> m_ready_promise; // [[ReadyPromise]] JS::NonnullGCPtr<WebIDL::Promise> m_ready_promise; // [[ReadyPromise]]
Vector<JS::NonnullGCPtr<FontFace>> m_loading_fonts {}; // [[LoadingFonts]] Vector<JS::NonnullGCPtr<FontFace>> m_loading_fonts {}; // [[LoadingFonts]]
Vector<JS::NonnullGCPtr<FontFace>> m_loaded_fonts {}; // [[LoadedFonts]] Vector<JS::NonnullGCPtr<FontFace>> m_loaded_fonts {}; // [[LoadedFonts]]

View file

@ -30,7 +30,7 @@ JS::NonnullGCPtr<ScreenOrientation> ScreenOrientation::create(JS::Realm& realm)
} }
// https://w3c.github.io/screen-orientation/#lock-method // https://w3c.github.io/screen-orientation/#lock-method
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> ScreenOrientation::lock(Bindings::OrientationLockType) WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> ScreenOrientation::lock(Bindings::OrientationLockType)
{ {
return WebIDL::NotSupportedError::create(realm(), "FIXME: ScreenOrientation::lock() is not implemented"_string); return WebIDL::NotSupportedError::create(realm(), "FIXME: ScreenOrientation::lock() is not implemented"_string);
} }

View file

@ -20,7 +20,7 @@ class ScreenOrientation final : public DOM::EventTarget {
public: public:
[[nodiscard]] static JS::NonnullGCPtr<ScreenOrientation> create(JS::Realm&); [[nodiscard]] static JS::NonnullGCPtr<ScreenOrientation> create(JS::Realm&);
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> lock(Bindings::OrientationLockType); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> lock(Bindings::OrientationLockType);
void unlock(); void unlock();
Bindings::OrientationType type() const; Bindings::OrientationType type() const;
WebIDL::UnsignedShort angle() const; WebIDL::UnsignedShort angle() const;

View file

@ -142,7 +142,7 @@ static bool check_clipboard_write_permission(JS::Realm& realm)
} }
// https://w3c.github.io/clipboard-apis/#dom-clipboard-writetext // https://w3c.github.io/clipboard-apis/#dom-clipboard-writetext
JS::NonnullGCPtr<JS::Promise> Clipboard::write_text(String data) JS::NonnullGCPtr<WebIDL::Promise> Clipboard::write_text(String data)
{ {
// 1. Let realm be this's relevant realm. // 1. Let realm be this's relevant realm.
auto& realm = HTML::relevant_realm(*this); auto& realm = HTML::relevant_realm(*this);
@ -194,7 +194,7 @@ JS::NonnullGCPtr<JS::Promise> Clipboard::write_text(String data)
}); });
// 4. Return p. // 4. Return p.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
} }

View file

@ -23,7 +23,7 @@ public:
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Clipboard>> construct_impl(JS::Realm&); static WebIDL::ExceptionOr<JS::NonnullGCPtr<Clipboard>> construct_impl(JS::Realm&);
virtual ~Clipboard() override; virtual ~Clipboard() override;
JS::NonnullGCPtr<JS::Promise> write_text(String); JS::NonnullGCPtr<WebIDL::Promise> write_text(String);
private: private:
Clipboard(JS::Realm&); Clipboard(JS::Realm&);

View file

@ -121,7 +121,7 @@ WebIDL::ExceptionOr<NormalizedAlgorithmAndParameter> normalize_an_algorithm(JS::
} }
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-encrypt // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-encrypt
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter) JS::NonnullGCPtr<WebIDL::Promise> SubtleCrypto::encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
auto& vm = this->vm(); auto& vm = this->vm();
@ -174,11 +174,11 @@ JS::NonnullGCPtr<JS::Promise> SubtleCrypto::encrypt(AlgorithmIdentifier const& a
WebIDL::resolve_promise(realm, promise, cipher_text.release_value()); WebIDL::resolve_promise(realm, promise, cipher_text.release_value());
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-decrypt // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-decrypt
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter) JS::NonnullGCPtr<WebIDL::Promise> SubtleCrypto::decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
auto& vm = this->vm(); auto& vm = this->vm();
@ -231,11 +231,11 @@ JS::NonnullGCPtr<JS::Promise> SubtleCrypto::decrypt(AlgorithmIdentifier const& a
WebIDL::resolve_promise(realm, promise, plain_text.release_value()); WebIDL::resolve_promise(realm, promise, plain_text.release_value());
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data) JS::NonnullGCPtr<WebIDL::Promise> SubtleCrypto::digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
auto& vm = this->vm(); auto& vm = this->vm();
@ -279,11 +279,11 @@ JS::NonnullGCPtr<JS::Promise> SubtleCrypto::digest(AlgorithmIdentifier const& al
WebIDL::resolve_promise(realm, promise, result.release_value()); WebIDL::resolve_promise(realm, promise, result.release_value());
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-generateKey // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-generateKey
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages) JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -339,11 +339,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::generate_key(
}); });
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey // https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages) JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -415,11 +415,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::import_key(Bi
WebIDL::resolve_promise(realm, promise, result); WebIDL::resolve_promise(realm, promise, result);
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-exportKey // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-exportKey
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key) JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// 1. Let format and key be the format and key parameters passed to the exportKey() method, respectively. // 1. Let format and key be the format and key parameters passed to the exportKey() method, respectively.
@ -461,11 +461,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::export_key(Bi
WebIDL::resolve_promise(realm, promise, result_or_error.release_value()); WebIDL::resolve_promise(realm, promise, result_or_error.release_value());
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-sign // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-sign
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter) JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
auto& vm = this->vm(); auto& vm = this->vm();
@ -518,11 +518,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::sign(Algorith
WebIDL::resolve_promise(realm, promise, result.release_value()); WebIDL::resolve_promise(realm, promise, result.release_value());
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-verify // https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-verify
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature_data, JS::Handle<WebIDL::BufferSource> const& data_parameter) JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature_data, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
auto& vm = this->vm(); auto& vm = this->vm();
@ -582,11 +582,11 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::verify(Algori
WebIDL::resolve_promise(realm, promise, result.release_value()); WebIDL::resolve_promise(realm, promise, result.release_value());
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits // https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length) JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length parameters passed to the deriveBits() method, respectively. // 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<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_bits(A
WebIDL::resolve_promise(realm, promise, result.release_value()); WebIDL::resolve_promise(realm, promise, result.release_value());
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages) JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> SubtleCrypto::derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
auto& vm = this->vm(); auto& vm = this->vm();
@ -722,7 +722,7 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_key(Al
WebIDL::resolve_promise(realm, promise, result.release_value()); WebIDL::resolve_promise(realm, promise, result.release_value());
}); });
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
SupportedAlgorithmsMap& supported_algorithms_internal() SupportedAlgorithmsMap& supported_algorithms_internal()

View file

@ -27,19 +27,19 @@ public:
virtual ~SubtleCrypto() override; virtual ~SubtleCrypto() override;
JS::NonnullGCPtr<JS::Promise> encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter); JS::NonnullGCPtr<WebIDL::Promise> encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::NonnullGCPtr<JS::Promise> decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter); JS::NonnullGCPtr<WebIDL::Promise> decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter); JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature, JS::Handle<WebIDL::BufferSource> const& data_parameter); JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::NonnullGCPtr<JS::Promise> digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data); JS::NonnullGCPtr<WebIDL::Promise> digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages); JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length); JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages); JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages); JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key); JS::ThrowCompletionOr<JS::NonnullGCPtr<WebIDL::Promise>> export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key);
private: private:
explicit SubtleCrypto(JS::Realm&); explicit SubtleCrypto(JS::Realm&);

View file

@ -55,7 +55,7 @@ bool BodyMixin::body_used() const
} }
// https://fetch.spec.whatwg.org/#dom-body-arraybuffer // https://fetch.spec.whatwg.org/#dom-body-arraybuffer
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::array_buffer() const WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::array_buffer() const
{ {
auto& vm = Bindings::main_thread_vm(); auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
@ -65,7 +65,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::array_buffer() con
} }
// https://fetch.spec.whatwg.org/#dom-body-blob // https://fetch.spec.whatwg.org/#dom-body-blob
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::blob() const WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::blob() const
{ {
auto& vm = Bindings::main_thread_vm(); auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
@ -75,7 +75,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::blob() const
} }
// https://fetch.spec.whatwg.org/#dom-body-bytes // https://fetch.spec.whatwg.org/#dom-body-bytes
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::bytes() const WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::bytes() const
{ {
auto& vm = Bindings::main_thread_vm(); auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
@ -85,7 +85,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::bytes() const
} }
// https://fetch.spec.whatwg.org/#dom-body-formdata // https://fetch.spec.whatwg.org/#dom-body-formdata
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::form_data() const WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::form_data() const
{ {
auto& vm = Bindings::main_thread_vm(); auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
@ -95,7 +95,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::form_data() const
} }
// https://fetch.spec.whatwg.org/#dom-body-json // https://fetch.spec.whatwg.org/#dom-body-json
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::json() const WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::json() const
{ {
auto& vm = Bindings::main_thread_vm(); auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
@ -105,7 +105,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::json() const
} }
// https://fetch.spec.whatwg.org/#dom-body-text // https://fetch.spec.whatwg.org/#dom-body-text
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> BodyMixin::text() const WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> BodyMixin::text() const
{ {
auto& vm = Bindings::main_thread_vm(); auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
@ -175,7 +175,7 @@ WebIDL::ExceptionOr<JS::Value> package_data(JS::Realm& realm, ByteBuffer bytes,
} }
// https://fetch.spec.whatwg.org/#concept-body-consume-body // https://fetch.spec.whatwg.org/#concept-body-consume-body
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> consume_body(JS::Realm& realm, BodyMixin const& object, PackageDataType type) WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> consume_body(JS::Realm& realm, BodyMixin const& object, PackageDataType type)
{ {
// 1. If object is unusable, then return a promise rejected with a TypeError. // 1. If object is unusable, then return a promise rejected with a TypeError.
if (object.is_unusable()) { if (object.is_unusable()) {
@ -229,7 +229,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> consume_body(JS::Realm& realm
} }
// 7. Return promise. // 7. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise().ptr()) }; return promise;
} }
} }

View file

@ -39,15 +39,15 @@ public:
[[nodiscard]] bool body_used() const; [[nodiscard]] bool body_used() const;
// JS API functions // JS API functions
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> array_buffer() const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> array_buffer() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> blob() const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> blob() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> bytes() const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> bytes() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> form_data() const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> form_data() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> json() const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> json() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> text() const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> text() const;
}; };
[[nodiscard]] WebIDL::ExceptionOr<JS::Value> package_data(JS::Realm&, ByteBuffer, PackageDataType, Optional<MimeSniff::MimeType> const&); [[nodiscard]] WebIDL::ExceptionOr<JS::Value> package_data(JS::Realm&, ByteBuffer, PackageDataType, Optional<MimeSniff::MimeType> const&);
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> consume_body(JS::Realm&, BodyMixin const&, PackageDataType); [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> consume_body(JS::Realm&, BodyMixin const&, PackageDataType);
} }

View file

@ -26,7 +26,7 @@
namespace Web::Fetch { namespace Web::Fetch {
// https://fetch.spec.whatwg.org/#dom-global-fetch // https://fetch.spec.whatwg.org/#dom-global-fetch
JS::NonnullGCPtr<JS::Promise> fetch(JS::VM& vm, RequestInfo const& input, RequestInit const& init) JS::NonnullGCPtr<WebIDL::Promise> fetch(JS::VM& vm, RequestInfo const& input, RequestInit const& init)
{ {
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
@ -39,7 +39,7 @@ JS::NonnullGCPtr<JS::Promise> fetch(JS::VM& vm, RequestInfo const& input, Reques
if (exception_or_request_object.is_exception()) { if (exception_or_request_object.is_exception()) {
auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, exception_or_request_object.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()); WebIDL::reject_promise(realm, promise_capability, *throw_completion.value());
return verify_cast<JS::Promise>(*promise_capability->promise().ptr()); return promise_capability;
} }
auto request_object = exception_or_request_object.release_value(); auto request_object = exception_or_request_object.release_value();
@ -52,7 +52,7 @@ JS::NonnullGCPtr<JS::Promise> fetch(JS::VM& vm, RequestInfo const& input, Reques
abort_fetch(realm, promise_capability, request, nullptr, request_object->signal()->reason()); abort_fetch(realm, promise_capability, request, nullptr, request_object->signal()->reason());
// 2. Return p. // 2. Return p.
return verify_cast<JS::Promise>(*promise_capability->promise().ptr()); return promise_capability;
} }
// 5. Let globalObject be requests clients global object. // 5. Let globalObject be requests clients global object.
@ -150,7 +150,7 @@ JS::NonnullGCPtr<JS::Promise> fetch(JS::VM& vm, RequestInfo const& input, Reques
}); });
// 13. Return p. // 13. Return p.
return verify_cast<JS::Promise>(*promise_capability->promise().ptr()); return promise_capability;
} }
// https://fetch.spec.whatwg.org/#abort-fetch // https://fetch.spec.whatwg.org/#abort-fetch

View file

@ -14,7 +14,7 @@
namespace Web::Fetch { namespace Web::Fetch {
JS::NonnullGCPtr<JS::Promise> fetch(JS::VM&, RequestInfo const& input, RequestInit const& init = {}); JS::NonnullGCPtr<WebIDL::Promise> fetch(JS::VM&, RequestInfo const& input, RequestInit const& init = {});
void abort_fetch(JS::Realm&, WebIDL::Promise const&, JS::NonnullGCPtr<Infrastructure::Request>, JS::GCPtr<Response>, JS::Value error); void abort_fetch(JS::Realm&, WebIDL::Promise const&, JS::NonnullGCPtr<Infrastructure::Request>, JS::GCPtr<Response>, JS::Value error);
} }

View file

@ -377,7 +377,7 @@ JS::NonnullGCPtr<Streams::ReadableStream> Blob::get_stream()
} }
// https://w3c.github.io/FileAPI/#dom-blob-text // https://w3c.github.io/FileAPI/#dom-blob-text
JS::NonnullGCPtr<JS::Promise> Blob::text() JS::NonnullGCPtr<WebIDL::Promise> Blob::text()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
auto& vm = realm.vm(); auto& vm = realm.vm();
@ -407,7 +407,7 @@ JS::NonnullGCPtr<JS::Promise> Blob::text()
} }
// https://w3c.github.io/FileAPI/#dom-blob-arraybuffer // https://w3c.github.io/FileAPI/#dom-blob-arraybuffer
JS::NonnullGCPtr<JS::Promise> Blob::array_buffer() JS::NonnullGCPtr<WebIDL::Promise> Blob::array_buffer()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -434,7 +434,7 @@ JS::NonnullGCPtr<JS::Promise> Blob::array_buffer()
} }
// https://w3c.github.io/FileAPI/#dom-blob-bytes // https://w3c.github.io/FileAPI/#dom-blob-bytes
JS::NonnullGCPtr<JS::Promise> Blob::bytes() JS::NonnullGCPtr<WebIDL::Promise> Blob::bytes()
{ {
auto& realm = this->realm(); auto& realm = this->realm();

View file

@ -48,9 +48,9 @@ public:
WebIDL::ExceptionOr<JS::NonnullGCPtr<Blob>> slice(Optional<i64> start = {}, Optional<i64> end = {}, Optional<String> const& content_type = {}); WebIDL::ExceptionOr<JS::NonnullGCPtr<Blob>> slice(Optional<i64> start = {}, Optional<i64> end = {}, Optional<String> const& content_type = {});
JS::NonnullGCPtr<Streams::ReadableStream> stream(); JS::NonnullGCPtr<Streams::ReadableStream> stream();
JS::NonnullGCPtr<JS::Promise> text(); JS::NonnullGCPtr<WebIDL::Promise> text();
JS::NonnullGCPtr<JS::Promise> array_buffer(); JS::NonnullGCPtr<WebIDL::Promise> array_buffer();
JS::NonnullGCPtr<JS::Promise> bytes(); JS::NonnullGCPtr<WebIDL::Promise> bytes();
ReadonlyBytes raw_bytes() const { return m_byte_buffer.bytes(); } ReadonlyBytes raw_bytes() const { return m_byte_buffer.bytes(); }

View file

@ -147,20 +147,23 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
// 10. In parallel, while true: // 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 { 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<MonotonicTime> progress_timer; Optional<MonotonicTime> progress_timer;
while (true) { while (true) {
auto& vm = realm.vm(); auto& vm = realm.vm();
// FIXME: Try harder to not reach into the [[Promise]] slot of chunkPromise
auto promise = JS::NonnullGCPtr { verify_cast<JS::Promise>(*chunk_promise->promise()) };
// 1. Wait for chunkPromise to be fulfilled or rejected. // 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([&]() { 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. // 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] // 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]() { 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)); dispatch_event(DOM::Event::create(realm, HTML::EventNames::loadstart));
})); }));
@ -169,14 +172,14 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
// 3. Set isFirstChunk to false. // 3. Set isFirstChunk to false.
is_first_chunk = false; is_first_chunk = false;
VERIFY(chunk_promise->result().is_object()); VERIFY(promise->result().is_object());
auto& result = chunk_promise->result().as_object(); auto& result = promise->result().as_object();
auto value = MUST(result.get(vm.names.value)); auto value = MUST(result.get(vm.names.value));
auto done = MUST(result.get(vm.names.done)); 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: // 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<JS::Uint8Array>(value.as_object())) { if (promise->state() == JS::Promise::State::Fulfilled && !done.as_bool() && is<JS::Uint8Array>(value.as_object())) {
// 1. Let bs be the byte sequence represented by the Uint8Array object. // 1. Let bs be the byte sequence represented by the Uint8Array object.
auto const& byte_sequence = verify_cast<JS::Uint8Array>(value.as_object()); auto const& byte_sequence = verify_cast<JS::Uint8Array>(value.as_object());
@ -200,7 +203,7 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
chunk_promise = reader->read(); 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: // 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]() { 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 frs state to "done". // 1. Set frs state to "done".
m_state = State::Done; m_state = State::Done;
@ -234,7 +237,7 @@ WebIDL::ExceptionOr<void> FileReader::read_operation(Blob& blob, Type type, Opti
return; return;
} }
// 6. Otherwise, if chunkPromise is rejected with an error error, queue a task to run the following steps and abort this algorithm: // 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]() { HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [this, &realm]() {
// 1. Set frs state to "done". // 1. Set frs state to "done".
m_state = State::Done; m_state = State::Done;
@ -250,6 +253,8 @@ WebIDL::ExceptionOr<void> 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. // 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;
} }
} }
}); });

View file

@ -313,7 +313,7 @@ JS::ThrowCompletionOr<void> CustomElementRegistry::define(String const& name, We
auto promise = promise_when_defined_iterator->value; auto promise = promise_when_defined_iterator->value;
// 2. Resolve promise with constructor. // 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. // 3. Delete the entry with key name from this CustomElementRegistry's when-defined promise map.
m_when_defined_promise_map.remove(name); m_when_defined_promise_map.remove(name);
@ -353,40 +353,34 @@ Optional<String> CustomElementRegistry::get_name(JS::Handle<WebIDL::CallbackType
} }
// https://html.spec.whatwg.org/multipage/custom-elements.html#dom-customelementregistry-whendefined // https://html.spec.whatwg.org/multipage/custom-elements.html#dom-customelementregistry-whendefined
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> CustomElementRegistry::when_defined(String const& name) WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> CustomElementRegistry::when_defined(String const& name)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// 1. If name is not a valid custom element name, then return a new promise rejected with a "SyntaxError" DOMException. // 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)) { if (!is_valid_custom_element_name(name))
auto promise = JS::Promise::create(realm); return WebIDL::create_rejected_promise(realm, WebIDL::SyntaxError::create(realm, MUST(String::formatted("'{}' is not a valid custom element name"sv, name))));
promise->reject(WebIDL::SyntaxError::create(realm, MUST(String::formatted("'{}' is not a valid custom element name"sv, name))));
return promise;
}
// 2. If this CustomElementRegistry contains an entry with name name, then return a new promise resolved with that entry's constructor. // 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<CustomElementDefinition> const& definition) { auto existing_definition_iterator = m_custom_element_definitions.find_if([&name](JS::Handle<CustomElementDefinition> const& definition) {
return definition->name() == name; return definition->name() == name;
}); });
if (existing_definition_iterator != m_custom_element_definitions.end()) { if (existing_definition_iterator != m_custom_element_definitions.end())
auto promise = JS::Promise::create(realm); return WebIDL::create_resolved_promise(realm, (*existing_definition_iterator)->constructor().callback);
promise->fulfill((*existing_definition_iterator)->constructor().callback);
return promise;
}
// 3. Let map be this CustomElementRegistry's when-defined promise map. // 3. Let map be this CustomElementRegistry's when-defined promise map.
// NOTE: Not necessary. // 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. // 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. // 5. Let promise be the value of the entry in map with key name.
JS::GCPtr<JS::Promise> promise; JS::GCPtr<WebIDL::Promise> promise;
auto existing_promise_iterator = m_when_defined_promise_map.find(name); auto existing_promise_iterator = m_when_defined_promise_map.find(name);
if (existing_promise_iterator != m_when_defined_promise_map.end()) { if (existing_promise_iterator != m_when_defined_promise_map.end()) {
promise = existing_promise_iterator->value; promise = existing_promise_iterator->value;
} else { } else {
promise = JS::Promise::create(realm); promise = WebIDL::create_promise(realm);
m_when_defined_promise_map.set(name, *promise); m_when_defined_promise_map.set(name, *promise);
} }

View file

@ -27,7 +27,7 @@ public:
JS::ThrowCompletionOr<void> define(String const& name, WebIDL::CallbackType* constructor, ElementDefinitionOptions options); JS::ThrowCompletionOr<void> define(String const& name, WebIDL::CallbackType* constructor, ElementDefinitionOptions options);
Variant<JS::Handle<WebIDL::CallbackType>, JS::Value> get(String const& name) const; Variant<JS::Handle<WebIDL::CallbackType>, JS::Value> get(String const& name) const;
Optional<String> get_name(JS::Handle<WebIDL::CallbackType> const& constructor) const; Optional<String> get_name(JS::Handle<WebIDL::CallbackType> const& constructor) const;
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> when_defined(String const& name); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> when_defined(String const& name);
void upgrade(JS::NonnullGCPtr<DOM::Node> root) const; void upgrade(JS::NonnullGCPtr<DOM::Node> root) const;
JS::GCPtr<CustomElementDefinition> get_definition_with_name_and_local_name(String const& name, String const& local_name) const; JS::GCPtr<CustomElementDefinition> 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 // 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. // 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<String, JS::NonnullGCPtr<JS::Promise>> m_when_defined_promise_map; OrderedHashMap<String, JS::NonnullGCPtr<WebIDL::Promise>> m_when_defined_promise_map;
}; };
} }

View file

@ -282,7 +282,7 @@ String HTMLImageElement::current_src() const
} }
// https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLImageElement::decode() const WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> HTMLImageElement::decode() const
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -360,7 +360,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLImageElement::decode() co
}); });
})); }));
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
Optional<ARIA::Role> HTMLImageElement::default_role() const Optional<ARIA::Role> HTMLImageElement::default_role() const

View file

@ -61,7 +61,7 @@ public:
String current_src() const; String current_src() const;
// https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> decode() const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> decode() const;
virtual Optional<ARIA::Role> default_role() const override; virtual Optional<ARIA::Role> default_role() const override;

View file

@ -334,7 +334,7 @@ void HTMLMediaElement::set_duration(double duration)
paintable->set_needs_display(); paintable->set_needs_display();
} }
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLMediaElement::play() WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> HTMLMediaElement::play()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -355,7 +355,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLMediaElement::play()
TRY(play_element()); TRY(play_element());
// 5. Return promise. // 5. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
// https://html.spec.whatwg.org/multipage/media.html#dom-media-pause // https://html.spec.whatwg.org/multipage/media.html#dom-media-pause

View file

@ -89,7 +89,7 @@ public:
bool paused() const { return m_paused; } bool paused() const { return m_paused; }
bool ended() const; bool ended() const;
bool potentially_playing() const; bool potentially_playing() const;
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> play(); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> play();
WebIDL::ExceptionOr<void> pause(); WebIDL::ExceptionOr<void> pause();
WebIDL::ExceptionOr<void> toggle_playback(); WebIDL::ExceptionOr<void> toggle_playback();

View file

@ -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 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-early-error-result
NavigationResult Navigation::early_error_result(AnyException e) 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 // 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 ]». // «[ "committed" → a promise rejected with e, "finished" → a promise rejected with e ]».
auto throw_completion = Bindings::dom_exception_to_throw_completion(vm, e);
return { return {
.committed = WebIDL::create_rejected_promise(realm(), *throw_completion.value())->promise(), .committed = WebIDL::create_rejected_promise_from_exception(realm, e),
.finished = WebIDL::create_rejected_promise(realm(), *throw_completion.value())->promise(), .finished = WebIDL::create_rejected_promise_from_exception(realm, e),
}; };
} }
@ -512,8 +511,8 @@ NavigationResult navigation_api_method_tracker_derived_result(JS::NonnullGCPtr<N
// A navigation API method tracker-derived result for a navigation API method tracker is a NavigationResult // A navigation API method tracker-derived result for a navigation API method tracker is a NavigationResult
/// dictionary instance given by «[ "committed" apiMethodTracker's committed promise, "finished" → apiMethodTracker's finished promise ]». /// dictionary instance given by «[ "committed" apiMethodTracker's committed promise, "finished" → apiMethodTracker's finished promise ]».
return { return {
api_method_tracker->committed_promise->promise(), api_method_tracker->committed_promise,
api_method_tracker->finished_promise->promise(), api_method_tracker->finished_promise,
}; };
} }
@ -639,8 +638,8 @@ WebIDL::ExceptionOr<NavigationResult> Navigation::perform_a_navigation_api_trave
// «[ "committed" → a promise resolved with current, "finished" → a promise resolved with current ]». // «[ "committed" → a promise resolved with current, "finished" → a promise resolved with current ]».
if (key == current->session_history_entry().navigation_api_key()) { if (key == current->session_history_entry().navigation_api_key()) {
return NavigationResult { return NavigationResult {
.committed = WebIDL::create_resolved_promise(realm, current)->promise(), .committed = WebIDL::create_resolved_promise(realm, current),
.finished = WebIDL::create_resolved_promise(realm, current)->promise() .finished = WebIDL::create_resolved_promise(realm, current)
}; };
} }
@ -788,7 +787,7 @@ void Navigation::abort_the_ongoing_navigation(JS::GCPtr<WebIDL::DOMException> er
// 11. If navigation's transition is not null, then: // 11. If navigation's transition is not null, then:
if (m_transition != nullptr) { if (m_transition != nullptr) {
// 1. Reject navigation's transition's finished promise with error. // 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. // 2. Set navigation's transition to null.
m_transition = nullptr; 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, // 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 // whose navigation type is navigationType, from entry is fromNHE, and whose finished promise is a new promise
// created in navigation's relevant realm. // 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. // 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. // 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 // 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. // 8. If navigation's transition is not null, then resolve navigation's transition's finished promise with undefined.
if (m_transition != nullptr) 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. // 9. Set navigation's transition to null.
m_transition = nullptr; }, 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. // 9. If navigation's transition is not null, then reject navigation's transition's finished promise with rejectionReason.
if (m_transition) 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. // 10. Set navigation's transition to null.
m_transition = nullptr; m_transition = nullptr;

View file

@ -39,9 +39,8 @@ struct NavigationReloadOptions : public NavigationOptions {
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationresult // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationresult
struct NavigationResult { struct NavigationResult {
// FIXME: Are we supposed to return a PromiseCapability (WebIDL::Promise) here? JS::NonnullGCPtr<WebIDL::Promise> committed;
JS::NonnullGCPtr<JS::Object> committed; JS::NonnullGCPtr<WebIDL::Promise> finished;
JS::NonnullGCPtr<JS::Object> finished;
}; };
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-method-tracker // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-method-tracker

View file

@ -5,23 +5,23 @@
*/ */
#include <LibJS/Heap/Heap.h> #include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Promise.h>
#include <LibJS/Runtime/Realm.h> #include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h> #include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/NavigationTransitionPrototype.h> #include <LibWeb/Bindings/NavigationTransitionPrototype.h>
#include <LibWeb/HTML/NavigationHistoryEntry.h> #include <LibWeb/HTML/NavigationHistoryEntry.h>
#include <LibWeb/HTML/NavigationTransition.h> #include <LibWeb/HTML/NavigationTransition.h>
#include <LibWeb/WebIDL/Promise.h>
namespace Web::HTML { namespace Web::HTML {
JS_DEFINE_ALLOCATOR(NavigationTransition); JS_DEFINE_ALLOCATOR(NavigationTransition);
JS::NonnullGCPtr<NavigationTransition> NavigationTransition::create(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr<NavigationHistoryEntry> from_entry, JS::GCPtr<JS::Promise> finished_promise) JS::NonnullGCPtr<NavigationTransition> NavigationTransition::create(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr<NavigationHistoryEntry> from_entry, JS::NonnullGCPtr<WebIDL::Promise> finished_promise)
{ {
return realm.heap().allocate<NavigationTransition>(realm, realm, navigation_type, from_entry, finished_promise); return realm.heap().allocate<NavigationTransition>(realm, realm, navigation_type, from_entry, finished_promise);
} }
NavigationTransition::NavigationTransition(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr<NavigationHistoryEntry> from_entry, JS::GCPtr<JS::Promise> finished_promise) NavigationTransition::NavigationTransition(JS::Realm& realm, Bindings::NavigationType navigation_type, JS::NonnullGCPtr<NavigationHistoryEntry> from_entry, JS::NonnullGCPtr<WebIDL::Promise> finished_promise)
: Bindings::PlatformObject(realm) : Bindings::PlatformObject(realm)
, m_navigation_type(navigation_type) , m_navigation_type(navigation_type)
, m_from_entry(from_entry) , m_from_entry(from_entry)

View file

@ -17,7 +17,7 @@ class NavigationTransition : public Bindings::PlatformObject {
JS_DECLARE_ALLOCATOR(NavigationTransition); JS_DECLARE_ALLOCATOR(NavigationTransition);
public: public:
[[nodiscard]] static JS::NonnullGCPtr<NavigationTransition> create(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr<NavigationHistoryEntry>, JS::GCPtr<JS::Promise>); [[nodiscard]] static JS::NonnullGCPtr<NavigationTransition> create(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr<NavigationHistoryEntry>, JS::NonnullGCPtr<WebIDL::Promise>);
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationtransition-navigationtype // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationtransition-navigationtype
Bindings::NavigationType navigation_type() const { return m_navigation_type; } Bindings::NavigationType navigation_type() const { return m_navigation_type; }
@ -26,12 +26,12 @@ public:
JS::NonnullGCPtr<NavigationHistoryEntry> from() const { return m_from_entry; } JS::NonnullGCPtr<NavigationHistoryEntry> from() const { return m_from_entry; }
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationtransition-finished // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationtransition-finished
JS::GCPtr<JS::Promise> finished() const { return m_finished_promise; } JS::NonnullGCPtr<WebIDL::Promise> finished() const { return m_finished_promise; }
virtual ~NavigationTransition() override; virtual ~NavigationTransition() override;
private: private:
NavigationTransition(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr<NavigationHistoryEntry>, JS::GCPtr<JS::Promise>); NavigationTransition(JS::Realm&, Bindings::NavigationType, JS::NonnullGCPtr<NavigationHistoryEntry>, JS::NonnullGCPtr<WebIDL::Promise>);
virtual void initialize(JS::Realm&) override; virtual void initialize(JS::Realm&) override;
virtual void visit_edges(JS::Cell::Visitor&) override; virtual void visit_edges(JS::Cell::Visitor&) override;
@ -43,7 +43,7 @@ private:
JS::NonnullGCPtr<NavigationHistoryEntry> m_from_entry; JS::NonnullGCPtr<NavigationHistoryEntry> m_from_entry;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-navigationtransition-finished // https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-navigationtransition-finished
JS::GCPtr<JS::Promise> m_finished_promise; JS::NonnullGCPtr<WebIDL::Promise> m_finished_promise;
}; };
} }

View file

@ -6,6 +6,7 @@
#pragma once #pragma once
#include <LibJS/Heap/GCPtr.h>
#include <LibWeb/Forward.h> #include <LibWeb/Forward.h>
namespace Web::HTML { namespace Web::HTML {

View file

@ -44,7 +44,7 @@ JS::NonnullGCPtr<ServiceWorkerContainer> ServiceWorkerContainer::create(JS::Real
} }
// https://w3c.github.io/ServiceWorker/#navigator-service-worker-register // https://w3c.github.io/ServiceWorker/#navigator-service-worker-register
JS::NonnullGCPtr<JS::Promise> ServiceWorkerContainer::register_(String script_url, RegistrationOptions const& options) JS::NonnullGCPtr<WebIDL::Promise> ServiceWorkerContainer::register_(String script_url, RegistrationOptions const& options)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// Note: The register(scriptURL, options) method creates or updates a service worker registration for the given scope url. // Note: The register(scriptURL, options) method creates or updates a service worker registration for the given scope url.
@ -76,7 +76,7 @@ JS::NonnullGCPtr<JS::Promise> ServiceWorkerContainer::register_(String script_ur
start_register(scope_url, parsed_script_url, p, client, client->creation_url, options.type, options.update_via_cache); start_register(scope_url, parsed_script_url, p, client, client->creation_url, options.type, options.update_via_cache);
// 8. Return p. // 8. Return p.
return verify_cast<JS::Promise>(*p->promise()); return p;
} }
// https://w3c.github.io/ServiceWorker/#start-register-algorithm // https://w3c.github.io/ServiceWorker/#start-register-algorithm

View file

@ -34,7 +34,7 @@ public:
[[nodiscard]] static JS::NonnullGCPtr<ServiceWorkerContainer> create(JS::Realm& realm); [[nodiscard]] static JS::NonnullGCPtr<ServiceWorkerContainer> create(JS::Realm& realm);
virtual ~ServiceWorkerContainer() override; virtual ~ServiceWorkerContainer() override;
JS::NonnullGCPtr<JS::Promise> register_(String script_url, RegistrationOptions const& options); JS::NonnullGCPtr<WebIDL::Promise> register_(String script_url, RegistrationOptions const& options);
#undef __ENUMERATE #undef __ENUMERATE
#define __ENUMERATE(attribute_name, event_name) \ #define __ENUMERATE(attribute_name, event_name) \

View file

@ -27,6 +27,7 @@
#include <LibWeb/HTML/Scripting/Environments.h> #include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/Scripting/ExceptionReporter.h> #include <LibWeb/HTML/Scripting/ExceptionReporter.h>
#include <LibWeb/HTML/Scripting/Fetching.h> #include <LibWeb/HTML/Scripting/Fetching.h>
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/HTML/StructuredSerialize.h> #include <LibWeb/HTML/StructuredSerialize.h>
#include <LibWeb/HTML/StructuredSerializeOptions.h> #include <LibWeb/HTML/StructuredSerializeOptions.h>
#include <LibWeb/HTML/Timer.h> #include <LibWeb/HTML/Timer.h>
@ -166,25 +167,26 @@ void WindowOrWorkerGlobalScopeMixin::queue_microtask(WebIDL::CallbackType& callb
} }
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-createimagebitmap // https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-createimagebitmap
JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, Optional<ImageBitmapOptions> options) const JS::NonnullGCPtr<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, Optional<ImageBitmapOptions> options) const
{ {
return create_image_bitmap_impl(image, {}, {}, {}, {}, options); return create_image_bitmap_impl(image, {}, {}, {}, {}, options);
} }
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-createimagebitmap // https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-createimagebitmap
JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional<ImageBitmapOptions> options) const JS::NonnullGCPtr<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional<ImageBitmapOptions> options) const
{ {
return create_image_bitmap_impl(image, sx, sy, sw, sh, options); return create_image_bitmap_impl(image, sx, sy, sw, sh, options);
} }
JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap_impl(ImageBitmapSource& image, Optional<WebIDL::Long> sx, Optional<WebIDL::Long> sy, Optional<WebIDL::Long> sw, Optional<WebIDL::Long> sh, Optional<ImageBitmapOptions>& options) const JS::NonnullGCPtr<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap_impl(ImageBitmapSource& image, Optional<WebIDL::Long> sx, Optional<WebIDL::Long> sy, Optional<WebIDL::Long> sw, Optional<WebIDL::Long> sh, Optional<ImageBitmapOptions>& 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. // 1. If either sw or sh is given and is 0, then return a promise rejected with a RangeError.
if (sw == 0 || sh == 0) { 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)); 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))); auto error = JS::RangeError::create(realm, move(error_message));
return promise; return WebIDL::create_rejected_promise(realm, move(error));
} }
// FIXME: // FIXME:
@ -195,14 +197,13 @@ JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitma
// FIXME: "Check the usability of the image argument" is only defined for CanvasImageSource, let's skip it for other types // FIXME: "Check the usability of the image argument" is only defined for CanvasImageSource, let's skip it for other types
if (image.has<CanvasImageSource>()) { if (image.has<CanvasImageSource>()) {
if (auto usability = check_usability_of_image(image.get<CanvasImageSource>()); usability.is_error() or usability.value() == CanvasImageSourceUsability::Bad) { if (auto usability = check_usability_of_image(image.get<CanvasImageSource>()); usability.is_error() or usability.value() == CanvasImageSourceUsability::Bad) {
auto promise = JS::Promise::create(this_impl().realm()); auto error = WebIDL::InvalidStateError::create(this_impl().realm(), "image argument is not usable"_string);
promise->reject(WebIDL::InvalidStateError::create(this_impl().realm(), "image argument is not usable"_string)); return WebIDL::create_rejected_promise_from_exception(realm, error);
return promise;
} }
} }
// 4. Let p be a new promise. // 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. // 5. Let imageBitmap be a new ImageBitmap object.
auto image_bitmap = ImageBitmap::create(this_impl().realm()); auto image_bitmap = ImageBitmap::create(this_impl().realm());
@ -226,7 +227,9 @@ JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitma
// imageData is corrupted in some fatal way such that the image dimensions cannot be obtained // 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 // (e.g., a vector graphic with no natural size), then reject p with an "InvalidStateError" DOMException
// and abort these steps. // 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<void> { auto on_successful_decode = [image_bitmap = JS::Handle(*image_bitmap), p = JS::Handle(*p)](Web::Platform::DecodedImage& result) -> ErrorOr<void> {
@ -236,8 +239,11 @@ JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitma
// or is disabled), or, if there is no such image, the first frame of the animation. // 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); image_bitmap->set_bitmap(result.frames.take_first().bitmap);
auto& realm = relevant_realm(p->promise());
// 5. Resolve p with imageBitmap. // 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 {}; return {};
}; };
@ -248,7 +254,9 @@ JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitma
dbgln("(STUBBED) createImageBitmap() for non-blob types"); dbgln("(STUBBED) createImageBitmap() for non-blob types");
(void)sx; (void)sx;
(void)sy; (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. // 7. Return p.
@ -273,7 +281,7 @@ WebIDL::ExceptionOr<JS::Value> WindowOrWorkerGlobalScopeMixin::structured_clone(
return deserialized; return deserialized;
} }
JS::NonnullGCPtr<JS::Promise> WindowOrWorkerGlobalScopeMixin::fetch(Fetch::RequestInfo const& input, Fetch::RequestInit const& init) const JS::NonnullGCPtr<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::fetch(Fetch::RequestInfo const& input, Fetch::RequestInit const& init) const
{ {
auto& vm = this_impl().vm(); auto& vm = this_impl().vm();
return Fetch::fetch(vm, input, init); return Fetch::fetch(vm, input, init);
@ -926,7 +934,7 @@ void WindowOrWorkerGlobalScopeMixin::notify_about_rejected_promises(Badge<EventL
.composed = false, .composed = false,
}, },
// Sadly we can't use .promise and .reason here, as we can't use the designator on the initialization of DOM::EventInit above. // Sadly we can't use .promise and .reason here, as we can't use the designator on the initialization of DOM::EventInit above.
/* .promise = */ JS::make_handle(*promise), /* .promise = */ *promise,
/* .reason = */ promise->result(), /* .reason = */ promise->result(),
}; };

View file

@ -39,10 +39,10 @@ public:
WebIDL::ExceptionOr<String> btoa(String const& data) const; WebIDL::ExceptionOr<String> btoa(String const& data) const;
WebIDL::ExceptionOr<String> atob(String const& data) const; WebIDL::ExceptionOr<String> atob(String const& data) const;
void queue_microtask(WebIDL::CallbackType&); void queue_microtask(WebIDL::CallbackType&);
JS::NonnullGCPtr<JS::Promise> create_image_bitmap(ImageBitmapSource image, Optional<ImageBitmapOptions> options = {}) const; JS::NonnullGCPtr<WebIDL::Promise> create_image_bitmap(ImageBitmapSource image, Optional<ImageBitmapOptions> options = {}) const;
JS::NonnullGCPtr<JS::Promise> create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional<ImageBitmapOptions> options = {}) const; JS::NonnullGCPtr<WebIDL::Promise> create_image_bitmap(ImageBitmapSource image, WebIDL::Long sx, WebIDL::Long sy, WebIDL::Long sw, WebIDL::Long sh, Optional<ImageBitmapOptions> options = {}) const;
WebIDL::ExceptionOr<JS::Value> structured_clone(JS::Value, StructuredSerializeOptions const&) const; WebIDL::ExceptionOr<JS::Value> structured_clone(JS::Value, StructuredSerializeOptions const&) const;
JS::NonnullGCPtr<JS::Promise> fetch(Fetch::RequestInfo const&, Fetch::RequestInit const&) const; JS::NonnullGCPtr<WebIDL::Promise> fetch(Fetch::RequestInfo const&, Fetch::RequestInit const&) const;
i32 set_timeout(TimerHandler, i32 timeout, JS::MarkedVector<JS::Value> arguments); i32 set_timeout(TimerHandler, i32 timeout, JS::MarkedVector<JS::Value> arguments);
i32 set_interval(TimerHandler, i32 timeout, JS::MarkedVector<JS::Value> arguments); i32 set_interval(TimerHandler, i32 timeout, JS::MarkedVector<JS::Value> arguments);
@ -105,7 +105,7 @@ private:
i32 run_timer_initialization_steps(TimerHandler handler, i32 timeout, JS::MarkedVector<JS::Value> arguments, Repeat repeat, Optional<i32> previous_id = {}); i32 run_timer_initialization_steps(TimerHandler handler, i32 timeout, JS::MarkedVector<JS::Value> arguments, Repeat repeat, Optional<i32> previous_id = {});
void run_steps_after_a_timeout_impl(i32 timeout, Function<void()> completion_step, Optional<i32> timer_key = {}); void run_steps_after_a_timeout_impl(i32 timeout, Function<void()> completion_step, Optional<i32> timer_key = {});
JS::NonnullGCPtr<JS::Promise> create_image_bitmap_impl(ImageBitmapSource& image, Optional<WebIDL::Long> sx, Optional<WebIDL::Long> sy, Optional<WebIDL::Long> sw, Optional<WebIDL::Long> sh, Optional<ImageBitmapOptions>& options) const; JS::NonnullGCPtr<WebIDL::Promise> create_image_bitmap_impl(ImageBitmapSource& image, Optional<WebIDL::Long> sx, Optional<WebIDL::Long> sy, Optional<WebIDL::Long> sw, Optional<WebIDL::Long> sh, Optional<ImageBitmapOptions>& options) const;
IDAllocator m_timer_id_allocator; IDAllocator m_timer_id_allocator;
HashMap<int, JS::NonnullGCPtr<Timer>> m_timers; HashMap<int, JS::NonnullGCPtr<Timer>> m_timers;

View file

@ -131,7 +131,7 @@ JS::NonnullGCPtr<WebIDL::Promise> readable_stream_cancel(ReadableStream& stream,
JS::create_heap_function(stream.heap(), [](JS::Value) -> WebIDL::ExceptionOr<JS::Value> { return JS::js_undefined(); }), JS::create_heap_function(stream.heap(), [](JS::Value) -> WebIDL::ExceptionOr<JS::Value> { 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 // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request
@ -431,9 +431,9 @@ public:
// 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]). // 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
auto cancel_result = readable_stream_cancel(m_stream, completion.value().value()); auto cancel_result = readable_stream_cancel(m_stream, completion.value().value());
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*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. // 4. Return.
return; return;
@ -584,8 +584,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_stream_default_tee(JS::Realm& r
auto cancel_result = readable_stream_cancel(stream, composite_reason); auto cancel_result = readable_stream_cancel(stream, composite_reason);
// 3. Resolve cancelPromise with cancelResult. // 3. Resolve cancelPromise with cancelResult.
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr()); WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise());
WebIDL::resolve_promise(realm, cancel_promise, cancel_value);
} }
// 4. Return cancelPromise. // 4. Return cancelPromise.
@ -609,8 +608,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_stream_default_tee(JS::Realm& r
auto cancel_result = readable_stream_cancel(stream, composite_reason); auto cancel_result = readable_stream_cancel(stream, composite_reason);
// 3. Resolve cancelPromise with cancelResult. // 3. Resolve cancelPromise with cancelResult.
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr()); WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise());
WebIDL::resolve_promise(realm, cancel_promise, cancel_value);
} }
// 4. Return cancelPromise. // 4. Return cancelPromise.
@ -744,9 +742,8 @@ public:
// 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]). // 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
auto cancel_result = readable_stream_cancel(m_stream, completion.value().value()); auto cancel_result = readable_stream_cancel(m_stream, completion.value().value());
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*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. // 4. Return.
return; return;
@ -909,9 +906,8 @@ public:
// 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]). // 3. Resolve cancelPromise with ! ReadableStreamCancel(stream, cloneResult.[[Value]]).
auto cancel_result = readable_stream_cancel(m_stream, completion.value().value()); auto cancel_result = readable_stream_cancel(m_stream, completion.value().value());
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*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. // 4. Return.
return; return;
@ -1221,8 +1217,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_byte_stream_tee(JS::Realm& real
auto cancel_result = readable_stream_cancel(stream, composite_reason); auto cancel_result = readable_stream_cancel(stream, composite_reason);
// 3. Resolve cancelPromise with cancelResult. // 3. Resolve cancelPromise with cancelResult.
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr()); WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise());
WebIDL::resolve_promise(realm, cancel_promise, cancel_value);
} }
// 4. Return cancelPromise. // 4. Return cancelPromise.
@ -1246,8 +1241,7 @@ WebIDL::ExceptionOr<ReadableStreamPair> readable_byte_stream_tee(JS::Realm& real
auto cancel_result = readable_stream_cancel(stream, composite_reason); auto cancel_result = readable_stream_cancel(stream, composite_reason);
// 3. Resolve cancelPromise with cancelResult. // 3. Resolve cancelPromise with cancelResult.
JS::NonnullGCPtr cancel_value = verify_cast<JS::Promise>(*cancel_result->promise().ptr()); WebIDL::resolve_promise(realm, cancel_promise, cancel_result->promise());
WebIDL::resolve_promise(realm, cancel_promise, cancel_value);
} }
// 4. Return cancelPromise. // 4. Return cancelPromise.
@ -1442,7 +1436,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> readable_stream_from_itera
}), }),
{}); {});
return WebIDL::create_resolved_promise(realm, react_result); return react_result;
}); });
// 5. Let cancelAlgorithm be the following steps, given reason: // 5. Let cancelAlgorithm be the following steps, given reason:
@ -1483,7 +1477,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> readable_stream_from_itera
}), }),
{}); {});
return WebIDL::create_resolved_promise(realm, react_result); return react_result;
}); });
// 6. Set stream to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, 0). // 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 // https://streams.spec.whatwg.org/#initialize-transform-stream
void initialize_transform_stream(TransformStream& stream, JS::NonnullGCPtr<JS::PromiseCapability> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm) void initialize_transform_stream(TransformStream& stream, JS::NonnullGCPtr<WebIDL::Promise> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm)
{ {
auto& realm = stream.realm(); auto& realm = stream.realm();
@ -4970,7 +4964,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_controller_perform_tr
return JS::throw_completion(reason); 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 // https://streams.spec.whatwg.org/#transform-stream-default-sink-abort-algorithm
@ -5031,7 +5025,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_sink_abort_algorithm(
})); }));
// 8. Return controller.[[finishPromise]]. // 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 // https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm
@ -5075,7 +5069,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_sink_close_algorithm(
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, readable->stored_error().as_string().utf8_string() }; 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 // https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm
@ -5118,7 +5112,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_sink_write_algorithm(
}), }),
{}); {});
return WebIDL::create_resolved_promise(realm, react_result); return react_result;
} }
// 4. Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk). // 4. Return ! TransformStreamDefaultControllerPerformTransform(controller, chunk).
@ -5196,7 +5190,7 @@ JS::NonnullGCPtr<WebIDL::Promise> transform_stream_default_source_cancel_algorit
})); }));
// 8. Return controller.[[finishPromise]]. // 8. Return controller.[[finishPromise]].
return JS::NonnullGCPtr { *controller->finish_promise() }; return *controller->finish_promise();
} }
// https://streams.spec.whatwg.org/#transform-stream-error // https://streams.spec.whatwg.org/#transform-stream-error

View file

@ -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_process_write(WritableStreamDefaultController&, JS::Value chunk);
void writable_stream_default_controller_write(WritableStreamDefaultController&, JS::Value chunk, JS::Value chunk_size); void writable_stream_default_controller_write(WritableStreamDefaultController&, JS::Value chunk, JS::Value chunk_size);
void initialize_transform_stream(TransformStream&, JS::NonnullGCPtr<JS::PromiseCapability> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm); void initialize_transform_stream(TransformStream&, JS::NonnullGCPtr<WebIDL::Promise> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm);
void set_up_transform_stream_default_controller(TransformStream&, TransformStreamDefaultController&, JS::NonnullGCPtr<TransformAlgorithm>, JS::NonnullGCPtr<FlushAlgorithm>, JS::NonnullGCPtr<CancelAlgorithm>); void set_up_transform_stream_default_controller(TransformStream&, TransformStreamDefaultController&, JS::NonnullGCPtr<TransformAlgorithm>, JS::NonnullGCPtr<FlushAlgorithm>, JS::NonnullGCPtr<CancelAlgorithm>);
void set_up_transform_stream_default_controller_from_transformer(TransformStream&, JS::Value transformer, Transformer&); void set_up_transform_stream_default_controller_from_transformer(TransformStream&, JS::Value transformer, Transformer&);
void transform_stream_default_controller_clear_algorithms(TransformStreamDefaultController&); void transform_stream_default_controller_clear_algorithms(TransformStreamDefaultController&);

View file

@ -90,18 +90,18 @@ bool ReadableStream::locked() const
} }
// https://streams.spec.whatwg.org/#rs-cancel // https://streams.spec.whatwg.org/#rs-cancel
JS::NonnullGCPtr<JS::Object> ReadableStream::cancel(JS::Value reason) JS::NonnullGCPtr<WebIDL::Promise> ReadableStream::cancel(JS::Value reason)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception. // 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_readable_stream_locked(*this)) { if (is_readable_stream_locked(*this)) {
auto exception = JS::TypeError::create(realm, "Cannot cancel a locked stream"sv); 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). // 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 // https://streams.spec.whatwg.org/#rs-get-reader
@ -141,29 +141,26 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> ReadableStream::pipe_throu
return JS::NonnullGCPtr { *transform.readable }; return JS::NonnullGCPtr { *transform.readable };
} }
JS::NonnullGCPtr<JS::Object> ReadableStream::pipe_to(WritableStream& destination, StreamPipeOptions const& options) JS::NonnullGCPtr<WebIDL::Promise> ReadableStream::pipe_to(WritableStream& destination, StreamPipeOptions const& options)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
auto& vm = realm.vm();
// 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception. // 1. If ! IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_readable_stream_locked(*this)) { if (is_readable_stream_locked(*this)) {
auto promise = WebIDL::create_promise(realm); return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::TypeError>("Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe a locked stream"sv));
WebIDL::reject_promise(realm, promise, JS::TypeError::create(realm, "Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe a locked stream"sv));
return promise->promise();
} }
// 2. If ! IsWritableStreamLocked(destination) is true, return a promise rejected with a TypeError exception. // 2. If ! IsWritableStreamLocked(destination) is true, return a promise rejected with a TypeError exception.
if (is_writable_stream_locked(destination)) { if (is_writable_stream_locked(destination)) {
auto promise = WebIDL::create_promise(realm); return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::TypeError>("Failed to execute 'pipeTo' on 'ReadableStream': Cannot pipe to a locked stream"sv));
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();
} }
// 3. Let signal be options["signal"] if it exists, or undefined otherwise. // 3. Let signal be options["signal"] if it exists, or undefined otherwise.
auto signal = options.signal ? JS::Value(options.signal) : JS::js_undefined(); auto signal = options.signal ? JS::Value(options.signal) : JS::js_undefined();
// 4. Return ! ReadableStreamPipeTo(this, destination, options["preventClose"], options["preventAbort"], options["preventCancel"], signal). // 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 // https://streams.spec.whatwg.org/#readablestream-tee

View file

@ -75,10 +75,10 @@ public:
virtual ~ReadableStream() override; virtual ~ReadableStream() override;
bool locked() const; bool locked() const;
JS::NonnullGCPtr<JS::Object> cancel(JS::Value reason); JS::NonnullGCPtr<WebIDL::Promise> cancel(JS::Value reason);
WebIDL::ExceptionOr<ReadableStreamReader> get_reader(ReadableStreamGetReaderOptions const& = {}); WebIDL::ExceptionOr<ReadableStreamReader> get_reader(ReadableStreamGetReaderOptions const& = {});
WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> pipe_through(ReadableWritablePair transform, StreamPipeOptions const& = {}); WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStream>> pipe_through(ReadableWritablePair transform, StreamPipeOptions const& = {});
JS::NonnullGCPtr<JS::Object> pipe_to(WritableStream& destination, StreamPipeOptions const& = {}); JS::NonnullGCPtr<WebIDL::Promise> pipe_to(WritableStream& destination, StreamPipeOptions const& = {});
WebIDL::ExceptionOr<ReadableStreamPair> tee(); WebIDL::ExceptionOr<ReadableStreamPair> tee();
void close(); void close();

View file

@ -107,7 +107,7 @@ private:
JS_DEFINE_ALLOCATOR(BYOBReaderReadIntoRequest); JS_DEFINE_ALLOCATOR(BYOBReaderReadIntoRequest);
// https://streams.spec.whatwg.org/#byob-reader-read // https://streams.spec.whatwg.org/#byob-reader-read
JS::NonnullGCPtr<JS::Promise> ReadableStreamBYOBReader::read(JS::Handle<WebIDL::ArrayBufferView>& view, ReadableStreamBYOBReaderReadOptions options) JS::NonnullGCPtr<WebIDL::Promise> ReadableStreamBYOBReader::read(JS::Handle<WebIDL::ArrayBufferView>& view, ReadableStreamBYOBReaderReadOptions options)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -177,6 +177,6 @@ JS::NonnullGCPtr<JS::Promise> ReadableStreamBYOBReader::read(JS::Handle<WebIDL::
readable_stream_byob_reader_read(*this, *view, options.min, *read_into_request); readable_stream_byob_reader_read(*this, *view, options.min, *read_into_request);
// 11. Return promise. // 11. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise()) }; return promise_capability;
} }
} }

View file

@ -51,7 +51,7 @@ public:
virtual ~ReadableStreamBYOBReader() override = default; virtual ~ReadableStreamBYOBReader() override = default;
JS::NonnullGCPtr<JS::Promise> read(JS::Handle<WebIDL::ArrayBufferView>&, ReadableStreamBYOBReaderReadOptions options = {}); JS::NonnullGCPtr<WebIDL::Promise> read(JS::Handle<WebIDL::ArrayBufferView>&, ReadableStreamBYOBReaderReadOptions options = {});
void release_lock(); void release_lock();

View file

@ -162,7 +162,7 @@ private:
JS_DEFINE_ALLOCATOR(DefaultReaderReadRequest); JS_DEFINE_ALLOCATOR(DefaultReaderReadRequest);
// https://streams.spec.whatwg.org/#default-reader-read // https://streams.spec.whatwg.org/#default-reader-read
JS::NonnullGCPtr<JS::Promise> ReadableStreamDefaultReader::read() JS::NonnullGCPtr<WebIDL::Promise> ReadableStreamDefaultReader::read()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -188,7 +188,7 @@ JS::NonnullGCPtr<JS::Promise> ReadableStreamDefaultReader::read()
readable_stream_default_reader_read(*this, read_request); readable_stream_default_reader_read(*this, read_request);
// 5. Return promise. // 5. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise()) }; return promise_capability;
} }
void ReadableStreamDefaultReader::read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request) void ReadableStreamDefaultReader::read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request)

View file

@ -77,7 +77,7 @@ public:
virtual ~ReadableStreamDefaultReader() override = default; virtual ~ReadableStreamDefaultReader() override = default;
JS::NonnullGCPtr<JS::Promise> read(); JS::NonnullGCPtr<WebIDL::Promise> read();
void read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request); void read_a_chunk(Fetch::Infrastructure::IncrementalReadLoopReadRequest& read_request);
void read_all_bytes(JS::NonnullGCPtr<ReadLoopReadRequest::SuccessSteps>, JS::NonnullGCPtr<ReadLoopReadRequest::FailureSteps>); void read_all_bytes(JS::NonnullGCPtr<ReadLoopReadRequest::SuccessSteps>, JS::NonnullGCPtr<ReadLoopReadRequest::FailureSteps>);

View file

@ -14,14 +14,14 @@
namespace Web::Streams { namespace Web::Streams {
// https://streams.spec.whatwg.org/#generic-reader-closed // https://streams.spec.whatwg.org/#generic-reader-closed
JS::GCPtr<JS::Promise> ReadableStreamGenericReaderMixin::closed() JS::GCPtr<WebIDL::Promise> ReadableStreamGenericReaderMixin::closed()
{ {
// 1. Return this.[[closedPromise]]. // 1. Return this.[[closedPromise]].
return JS::GCPtr { verify_cast<JS::Promise>(*m_closed_promise->promise()) }; return m_closed_promise;
} }
// https://streams.spec.whatwg.org/#generic-reader-cancel // https://streams.spec.whatwg.org/#generic-reader-cancel
JS::NonnullGCPtr<JS::Promise> ReadableStreamGenericReaderMixin::cancel(JS::Value reason) JS::NonnullGCPtr<WebIDL::Promise> ReadableStreamGenericReaderMixin::cancel(JS::Value reason)
{ {
// 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
if (!m_stream) { if (!m_stream) {
@ -30,8 +30,7 @@ JS::NonnullGCPtr<JS::Promise> ReadableStreamGenericReaderMixin::cancel(JS::Value
} }
// 2. Return ! ReadableStreamReaderGenericCancel(this, reason). // 2. Return ! ReadableStreamReaderGenericCancel(this, reason).
auto promise_capability = readable_stream_reader_generic_cancel(*this, reason); return readable_stream_reader_generic_cancel(*this, reason);
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise().ptr()) };
} }
ReadableStreamGenericReaderMixin::ReadableStreamGenericReaderMixin(JS::Realm& realm) ReadableStreamGenericReaderMixin::ReadableStreamGenericReaderMixin(JS::Realm& realm)

View file

@ -19,9 +19,9 @@ class ReadableStreamGenericReaderMixin {
public: public:
virtual ~ReadableStreamGenericReaderMixin() = default; virtual ~ReadableStreamGenericReaderMixin() = default;
JS::GCPtr<JS::Promise> closed(); JS::GCPtr<WebIDL::Promise> closed();
JS::NonnullGCPtr<JS::Promise> cancel(JS::Value reason); JS::NonnullGCPtr<WebIDL::Promise> cancel(JS::Value reason);
JS::GCPtr<ReadableStream> stream() const { return m_stream; } JS::GCPtr<ReadableStream> stream() const { return m_stream; }
void set_stream(JS::GCPtr<ReadableStream> stream) { m_stream = stream; } void set_stream(JS::GCPtr<ReadableStream> stream) { m_stream = stream; }

View file

@ -58,39 +58,39 @@ bool WritableStream::locked() const
} }
// https://streams.spec.whatwg.org/#ws-close // https://streams.spec.whatwg.org/#ws-close
JS::GCPtr<JS::Object> WritableStream::close() JS::GCPtr<WebIDL::Promise> WritableStream::close()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception. // 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_writable_stream_locked(*this)) { if (is_writable_stream_locked(*this)) {
auto exception = JS::TypeError::create(realm, "Cannot close a locked stream"sv); 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. // 2. If ! WritableStreamCloseQueuedOrInFlight(this) is true, return a promise rejected with a TypeError exception.
if (writable_stream_close_queued_or_in_flight(*this)) { 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); 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). // 3. Return ! WritableStreamClose(this).
return writable_stream_close(*this)->promise(); return writable_stream_close(*this);
} }
// https://streams.spec.whatwg.org/#ws-abort // https://streams.spec.whatwg.org/#ws-abort
JS::GCPtr<JS::Object> WritableStream::abort(JS::Value reason) JS::GCPtr<WebIDL::Promise> WritableStream::abort(JS::Value reason)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception. // 1. If ! IsWritableStreamLocked(this) is true, return a promise rejected with a TypeError exception.
if (is_writable_stream_locked(*this)) { if (is_writable_stream_locked(*this)) {
auto exception = JS::TypeError::create(realm, "Cannot abort a locked stream"sv); 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). // 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 // https://streams.spec.whatwg.org/#ws-get-writer

View file

@ -49,8 +49,8 @@ public:
virtual ~WritableStream() = default; virtual ~WritableStream() = default;
bool locked() const; bool locked() const;
JS::GCPtr<JS::Object> abort(JS::Value reason); JS::GCPtr<WebIDL::Promise> abort(JS::Value reason);
JS::GCPtr<JS::Object> close(); JS::GCPtr<WebIDL::Promise> close();
WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStreamDefaultWriter>> get_writer(); WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStreamDefaultWriter>> get_writer();
bool backpressure() const { return m_backpressure; } bool backpressure() const { return m_backpressure; }

View file

@ -27,10 +27,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WritableStreamDefaultWriter>> WritableStrea
} }
// https://streams.spec.whatwg.org/#default-writer-closed // https://streams.spec.whatwg.org/#default-writer-closed
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::closed() JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::closed()
{ {
// 1. Return this.[[closedPromise]]. // 1. Return this.[[closedPromise]].
return m_closed_promise->promise(); return m_closed_promise;
} }
// https://streams.spec.whatwg.org/#default-writer-desired-size // https://streams.spec.whatwg.org/#default-writer-desired-size
@ -45,29 +45,29 @@ WebIDL::ExceptionOr<Optional<double>> WritableStreamDefaultWriter::desired_size(
} }
// https://streams.spec.whatwg.org/#default-writer-ready // https://streams.spec.whatwg.org/#default-writer-ready
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::ready() JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::ready()
{ {
// 1. Return this.[[readyPromise]]. // 1. Return this.[[readyPromise]].
return m_ready_promise->promise(); return m_ready_promise;
} }
// https://streams.spec.whatwg.org/#default-writer-abort // https://streams.spec.whatwg.org/#default-writer-abort
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::abort(JS::Value reason) JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::abort(JS::Value reason)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
if (!m_stream) { if (!m_stream) {
auto exception = JS::TypeError::create(realm, "Cannot abort a writer that has no locked stream"sv); 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). // 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 // https://streams.spec.whatwg.org/#default-writer-close
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::close() JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::close()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -76,17 +76,17 @@ JS::GCPtr<JS::Object> WritableStreamDefaultWriter::close()
// 2. If stream is undefined, return a promise rejected with a TypeError exception. // 2. If stream is undefined, return a promise rejected with a TypeError exception.
if (!m_stream) { if (!m_stream) {
auto exception = JS::TypeError::create(realm, "Cannot close a writer that has no locked stream"sv); 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. // 3. If ! WritableStreamCloseQueuedOrInFlight(stream) is true, return a promise rejected with a TypeError exception.
if (writable_stream_close_queued_or_in_flight(*m_stream)) { 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); 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). // 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 // 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 // https://streams.spec.whatwg.org/#default-writer-write
JS::GCPtr<JS::Object> WritableStreamDefaultWriter::write(JS::Value chunk) JS::GCPtr<WebIDL::Promise> WritableStreamDefaultWriter::write(JS::Value chunk)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
// 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception. // 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.
if (!m_stream) { if (!m_stream) {
auto exception = JS::TypeError::create(realm, "Cannot write to a writer that has no locked stream"sv); 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). // 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) WritableStreamDefaultWriter::WritableStreamDefaultWriter(JS::Realm& realm)

View file

@ -25,13 +25,13 @@ public:
virtual ~WritableStreamDefaultWriter() override = default; virtual ~WritableStreamDefaultWriter() override = default;
JS::GCPtr<JS::Object> closed(); JS::GCPtr<WebIDL::Promise> closed();
WebIDL::ExceptionOr<Optional<double>> desired_size() const; WebIDL::ExceptionOr<Optional<double>> desired_size() const;
JS::GCPtr<JS::Object> ready(); JS::GCPtr<WebIDL::Promise> ready();
JS::GCPtr<JS::Object> abort(JS::Value reason); JS::GCPtr<WebIDL::Promise> abort(JS::Value reason);
JS::GCPtr<JS::Object> close(); JS::GCPtr<WebIDL::Promise> close();
void release_lock(); void release_lock();
JS::GCPtr<JS::Object> write(JS::Value chunk); JS::GCPtr<WebIDL::Promise> write(JS::Value chunk);
JS::GCPtr<WebIDL::Promise> closed_promise() { return m_closed_promise; } JS::GCPtr<WebIDL::Promise> closed_promise() { return m_closed_promise; }
void set_closed_promise(JS::GCPtr<WebIDL::Promise> value) { m_closed_promise = value; } void set_closed_promise(JS::GCPtr<WebIDL::Promise> value) { m_closed_promise = value; }

View file

@ -19,12 +19,14 @@
#include <LibJS/Runtime/TypedArray.h> #include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/VM.h> #include <LibJS/Runtime/VM.h>
#include <LibWasm/AbstractMachine/Validator.h> #include <LibWasm/AbstractMachine/Validator.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/WebAssembly/Instance.h> #include <LibWeb/WebAssembly/Instance.h>
#include <LibWeb/WebAssembly/Memory.h> #include <LibWeb/WebAssembly/Memory.h>
#include <LibWeb/WebAssembly/Module.h> #include <LibWeb/WebAssembly/Module.h>
#include <LibWeb/WebAssembly/Table.h> #include <LibWeb/WebAssembly/Table.h>
#include <LibWeb/WebAssembly/WebAssembly.h> #include <LibWeb/WebAssembly/WebAssembly.h>
#include <LibWeb/WebIDL/Buffers.h> #include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/Promise.h>
namespace Web::WebAssembly { namespace Web::WebAssembly {
@ -80,26 +82,25 @@ bool validate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes)
} }
// https://webassembly.github.io/spec/js-api/#dom-webassembly-compile // https://webassembly.github.io/spec/js-api/#dom-webassembly-compile
WebIDL::ExceptionOr<JS::Value> compile(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes) WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> compile(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes)
{ {
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
// FIXME: This shouldn't block! // FIXME: This shouldn't block!
auto compiled_module_or_error = Detail::parse_module(vm, bytes->raw_object()); 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()) { 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 { } else {
auto module_object = vm.heap().allocate<Module>(realm, realm, compiled_module_or_error.release_value()); auto module_object = vm.heap().allocate<Module>(realm, realm, compiled_module_or_error.release_value());
promise->fulfill(module_object); WebIDL::resolve_promise(realm, promise, module_object);
} }
return promise; return promise;
} }
// https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate // https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object) WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM& vm, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object)
{ {
// FIXME: Implement the importObject parameter. // FIXME: Implement the importObject parameter.
(void)import_object; (void)import_object;
@ -108,10 +109,10 @@ WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::Buffer
// FIXME: This shouldn't block! // FIXME: This shouldn't block!
auto compiled_module_or_error = Detail::parse_module(vm, bytes->raw_object()); 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()) { 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; return promise;
} }
@ -119,7 +120,7 @@ WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::Buffer
auto result = Detail::instantiate_module(vm, compiled_module->module); auto result = Detail::instantiate_module(vm, compiled_module->module);
if (result.is_error()) { if (result.is_error()) {
promise->reject(*result.release_error().value()); WebIDL::reject_promise(realm, promise, result.error_value());
} else { } else {
auto module_object = vm.heap().allocate<Module>(realm, realm, move(compiled_module)); auto module_object = vm.heap().allocate<Module>(realm, realm, move(compiled_module));
auto instance_object = vm.heap().allocate<Instance>(realm, realm, result.release_value()); auto instance_object = vm.heap().allocate<Instance>(realm, realm, result.release_value());
@ -127,29 +128,30 @@ WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, JS::Handle<WebIDL::Buffer
auto object = JS::Object::create(realm, nullptr); auto object = JS::Object::create(realm, nullptr);
object->define_direct_property("module", module_object, JS::default_attributes); object->define_direct_property("module", module_object, JS::default_attributes);
object->define_direct_property("instance", instance_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; return promise;
} }
// https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate-moduleobject-importobject // https://webassembly.github.io/spec/js-api/#dom-webassembly-instantiate-moduleobject-importobject
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM& vm, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object) WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM& vm, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object)
{ {
// FIXME: Implement the importObject parameter. // FIXME: Implement the importObject parameter.
(void)import_object; (void)import_object;
auto& realm = *vm.current_realm(); 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 const& compiled_module = module_object.compiled_module();
auto result = Detail::instantiate_module(vm, compiled_module->module); auto result = Detail::instantiate_module(vm, compiled_module->module);
if (result.is_error()) { if (result.is_error()) {
promise->reject(*result.release_error().value()); WebIDL::reject_promise(realm, promise, result.error_value());
} else { } else {
auto instance_object = vm.heap().allocate<Instance>(realm, realm, result.release_value()); auto instance_object = vm.heap().allocate<Instance>(realm, realm, result.release_value());
promise->fulfill(instance_object); WebIDL::resolve_promise(realm, promise, instance_object);
} }
return promise; return promise;

View file

@ -22,10 +22,10 @@ void visit_edges(JS::Object&, JS::Cell::Visitor&);
void finalize(JS::Object&); void finalize(JS::Object&);
bool validate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes); bool validate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes);
WebIDL::ExceptionOr<JS::Value> compile(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> compile(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes);
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM&, JS::Handle<WebIDL::BufferSource>& bytes, Optional<JS::Handle<JS::Object>>& import_object);
WebIDL::ExceptionOr<JS::Value> instantiate(JS::VM&, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> instantiate(JS::VM&, Module const& module_object, Optional<JS::Handle<JS::Object>>& import_object);
namespace Detail { namespace Detail {
struct CompiledWebAssemblyModule : public RefCounted<CompiledWebAssemblyModule> { struct CompiledWebAssemblyModule : public RefCounted<CompiledWebAssemblyModule> {

View file

@ -103,7 +103,7 @@ AudioTimestamp AudioContext::get_output_timestamp()
} }
// https://www.w3.org/TR/webaudio/#dom-audiocontext-resume // https://www.w3.org/TR/webaudio/#dom-audiocontext-resume
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::resume() WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> AudioContext::resume()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -118,7 +118,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::resume()
// 3. If the [[control thread state]] on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise. // 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) { if (state() == Bindings::AudioContextState::Closed) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string)); WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string));
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
// 4. Set [[suspended by user]] to true. // 4. Set [[suspended by user]] to true.
@ -187,11 +187,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::resume()
})); }));
// 8. Return promise. // 8. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
// https://www.w3.org/TR/webaudio/#dom-audiocontext-suspend // https://www.w3.org/TR/webaudio/#dom-audiocontext-suspend
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::suspend() WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> AudioContext::suspend()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -206,7 +206,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::suspend()
// 3. If the [[control thread state]] on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise. // 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) { if (state() == Bindings::AudioContextState::Closed) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string)); WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string));
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
// 4. Append promise to [[pending promises]]. // 4. Append promise to [[pending promises]].
@ -244,11 +244,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::suspend()
})); }));
// 8. Return promise. // 8. Return promise.
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
// https://www.w3.org/TR/webaudio/#dom-audiocontext-close // https://www.w3.org/TR/webaudio/#dom-audiocontext-close
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::close() WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> AudioContext::close()
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -263,7 +263,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::close()
// 3. If the [[control thread state]] flag on the AudioContext is closed reject the promise with InvalidStateError, abort these steps, returning promise. // 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) { if (state() == Bindings::AudioContextState::Closed) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string)); WebIDL::reject_promise(realm, promise, WebIDL::InvalidStateError::create(realm, "Audio context is already closed."_string));
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
// 4. Set the [[control thread state]] flag on the AudioContext to closed. // 4. Set the [[control thread state]] flag on the AudioContext to closed.
@ -296,7 +296,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> AudioContext::close()
})); }));
// 6. Return promise // 6. Return promise
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) }; return promise;
} }
// FIXME: Actually implement the rendering thread // FIXME: Actually implement the rendering thread

View file

@ -35,9 +35,9 @@ public:
double base_latency() const { return m_base_latency; } double base_latency() const { return m_base_latency; }
double output_latency() const { return m_output_latency; } double output_latency() const { return m_output_latency; }
AudioTimestamp get_output_timestamp(); AudioTimestamp get_output_timestamp();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> resume(); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> resume();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> suspend(); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> suspend();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> close(); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> close();
private: private:
explicit AudioContext(JS::Realm&, AudioContextOptions const& context_options); explicit AudioContext(JS::Realm&, AudioContextOptions const& context_options);

View file

@ -128,7 +128,7 @@ void BaseAudioContext::queue_a_media_element_task(JS::NonnullGCPtr<JS::HeapFunct
} }
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-decodeaudiodata // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-decodeaudiodata
JS::NonnullGCPtr<JS::Promise> BaseAudioContext::decode_audio_data(JS::Handle<WebIDL::BufferSource> audio_data, JS::GCPtr<WebIDL::CallbackType> success_callback, JS::GCPtr<WebIDL::CallbackType> error_callback) JS::NonnullGCPtr<WebIDL::Promise> BaseAudioContext::decode_audio_data(JS::Handle<WebIDL::BufferSource> audio_data, JS::GCPtr<WebIDL::CallbackType> success_callback, JS::GCPtr<WebIDL::CallbackType> error_callback)
{ {
auto& realm = this->realm(); auto& realm = this->realm();
@ -178,7 +178,7 @@ JS::NonnullGCPtr<JS::Promise> BaseAudioContext::decode_audio_data(JS::Handle<Web
} }
// 5. Return promise. // 5. Return promise.
return verify_cast<JS::Promise>(*promise->promise()); return promise;
} }
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-decodeaudiodata // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-decodeaudiodata

View file

@ -61,7 +61,7 @@ public:
WebIDL::ExceptionOr<JS::NonnullGCPtr<DynamicsCompressorNode>> create_dynamics_compressor(); WebIDL::ExceptionOr<JS::NonnullGCPtr<DynamicsCompressorNode>> create_dynamics_compressor();
JS::NonnullGCPtr<GainNode> create_gain(); JS::NonnullGCPtr<GainNode> create_gain();
JS::NonnullGCPtr<JS::Promise> decode_audio_data(JS::Handle<WebIDL::BufferSource>, JS::GCPtr<WebIDL::CallbackType>, JS::GCPtr<WebIDL::CallbackType>); JS::NonnullGCPtr<WebIDL::Promise> decode_audio_data(JS::Handle<WebIDL::BufferSource>, JS::GCPtr<WebIDL::CallbackType>, JS::GCPtr<WebIDL::CallbackType>);
protected: protected:
explicit BaseAudioContext(JS::Realm&, float m_sample_rate = 0); explicit BaseAudioContext(JS::Realm&, float m_sample_rate = 0);

View file

@ -32,17 +32,17 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<OfflineAudioContext>> OfflineAudioContext::
OfflineAudioContext::~OfflineAudioContext() = default; OfflineAudioContext::~OfflineAudioContext() = default;
// https://webaudio.github.io/web-audio-api/#dom-offlineaudiocontext-startrendering // https://webaudio.github.io/web-audio-api/#dom-offlineaudiocontext-startrendering
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> OfflineAudioContext::start_rendering() WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> OfflineAudioContext::start_rendering()
{ {
return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::start_rendering"_string); return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::start_rendering"_string);
} }
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> OfflineAudioContext::resume() WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> OfflineAudioContext::resume()
{ {
return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::resume"_string); return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::resume"_string);
} }
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> OfflineAudioContext::suspend(double suspend_time) WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> OfflineAudioContext::suspend(double suspend_time)
{ {
(void)suspend_time; (void)suspend_time;
return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::suspend"_string); return WebIDL::NotSupportedError::create(realm(), "FIXME: Implement OfflineAudioContext::suspend"_string);

View file

@ -32,9 +32,9 @@ public:
virtual ~OfflineAudioContext() override; virtual ~OfflineAudioContext() override;
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> start_rendering(); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> start_rendering();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> resume(); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> resume();
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> suspend(double suspend_time); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> suspend(double suspend_time);
WebIDL::UnsignedLong length() const; WebIDL::UnsignedLong length() const;

View file

@ -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 }; HTML::TemporaryExecutionContext execution_context { document->relevant_settings_object(), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
// 7. Let promise be a new Promise. // 7. Let promise be a new Promise.
auto promise_capability = WebIDL::create_promise(realm); auto promise = WebIDL::create_promise(realm);
JS::NonnullGCPtr promise { verify_cast<JS::Promise>(*promise_capability->promise()) };
// 8. Run the following substeps in parallel: // 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() }; 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. // 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)); 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. // 2. Upon fulfillment of scriptPromise with value v, resolve promise with value v.
if (script_result.has_value()) { 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. // 3. Upon rejection of scriptPromise with value r, reject promise with value r.
if (script_result.is_throw_completion()) { 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(); return JS::js_undefined();
timer->stop(); timer->stop();
auto json_value_or_error = json_clone(realm, browsing_context, promise->result()); auto promise_promise = JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise()) };
auto json_value_or_error = json_clone(realm, browsing_context, promise_promise->result());
if (json_value_or_error.is_error()) { if (json_value_or_error.is_error()) {
auto error_object = JsonObject {}; auto error_object = JsonObject {};
error_object.set("name", "Error"); 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. // 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. // 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() }); 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. // 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() }); on_complete->function()({ ExecuteScriptResultType::PromiseRejected, json_value_or_error.release_value() });
} }
return JS::js_undefined(); 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<JS::Value> arguments, Optional<u64> const& timeout_ms, JS::NonnullGCPtr<OnScriptComplete> on_complete) void execute_async_script(HTML::BrowsingContext const& browsing_context, ByteString body, JS::MarkedVector<JS::Value> arguments, Optional<u64> const& timeout_ms, JS::NonnullGCPtr<OnScriptComplete> on_complete)

View file

@ -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 // https://webidl.spec.whatwg.org/#dfn-perform-steps-once-promise-is-settled
JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback) JS::NonnullGCPtr<Promise> react_to_promise(Promise const& promise, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback)
{ {
auto& realm = promise.promise()->shape().realm(); auto& realm = promise.promise()->shape().realm();
auto& vm = realm.vm(); auto& vm = realm.vm();
@ -140,13 +140,17 @@ JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const& promise, JS::GCPtr
auto new_capability = MUST(JS::new_promise_capability(vm, constructor)); auto new_capability = MUST(JS::new_promise_capability(vm, constructor));
// 7. Return PerformPromiseThen(promise.[[Promise]], onFulfilled, onRejected, newCapability). // 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<JS::Promise>(promise.promise().ptr()); auto promise_object = verify_cast<JS::Promise>(promise.promise().ptr());
auto value = promise_object->perform_then(on_fulfilled, on_rejected, new_capability); auto value = promise_object->perform_then(on_fulfilled, on_rejected, new_capability);
return verify_cast<JS::Promise>(value.as_object());
VERIFY(value == new_capability->promise());
return new_capability;
} }
// https://webidl.spec.whatwg.org/#upon-fulfillment // https://webidl.spec.whatwg.org/#upon-fulfillment
JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps) JS::NonnullGCPtr<Promise> upon_fulfillment(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps)
{ {
// 1. Return the result of reacting to promise: // 1. Return the result of reacting to promise:
return react_to_promise(promise, return react_to_promise(promise,
@ -157,7 +161,7 @@ JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const& promise, JS::Nonnu
} }
// https://webidl.spec.whatwg.org/#upon-rejection // https://webidl.spec.whatwg.org/#upon-rejection
JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps) JS::NonnullGCPtr<Promise> upon_rejection(Promise const& promise, JS::NonnullGCPtr<ReactionSteps> steps)
{ {
// 1. Return the result of reacting to promise: // 1. Return the result of reacting to promise:
return react_to_promise(promise, {}, return react_to_promise(promise, {},
@ -287,11 +291,10 @@ void wait_for_all(JS::Realm& realm, Vector<JS::NonnullGCPtr<Promise>> const& pro
} }
} }
JS::NonnullGCPtr<JS::Promise> create_rejected_promise_from_exception(JS::Realm& realm, Exception exception) JS::NonnullGCPtr<Promise> create_rejected_promise_from_exception(JS::Realm& realm, Exception exception)
{ {
auto throw_completion = Bindings::dom_exception_to_throw_completion(realm.vm(), move(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 WebIDL::create_rejected_promise(realm, *throw_completion.value());
return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise_capability->promise().ptr()) };
} }
} }

View file

@ -27,13 +27,13 @@ JS::NonnullGCPtr<Promise> create_resolved_promise(JS::Realm&, JS::Value);
JS::NonnullGCPtr<Promise> create_rejected_promise(JS::Realm&, JS::Value); JS::NonnullGCPtr<Promise> create_rejected_promise(JS::Realm&, JS::Value);
void resolve_promise(JS::Realm&, Promise const&, JS::Value = JS::js_undefined()); void resolve_promise(JS::Realm&, Promise const&, JS::Value = JS::js_undefined());
void reject_promise(JS::Realm&, Promise const&, JS::Value); void reject_promise(JS::Realm&, Promise const&, JS::Value);
JS::NonnullGCPtr<JS::Promise> react_to_promise(Promise const&, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback); JS::NonnullGCPtr<Promise> react_to_promise(Promise const&, JS::GCPtr<ReactionSteps> on_fulfilled_callback, JS::GCPtr<ReactionSteps> on_rejected_callback);
JS::NonnullGCPtr<JS::Promise> upon_fulfillment(Promise const&, JS::NonnullGCPtr<ReactionSteps>); JS::NonnullGCPtr<Promise> upon_fulfillment(Promise const&, JS::NonnullGCPtr<ReactionSteps>);
JS::NonnullGCPtr<JS::Promise> upon_rejection(Promise const&, JS::NonnullGCPtr<ReactionSteps>); JS::NonnullGCPtr<Promise> upon_rejection(Promise const&, JS::NonnullGCPtr<ReactionSteps>);
void mark_promise_as_handled(Promise const&); void mark_promise_as_handled(Promise const&);
void wait_for_all(JS::Realm&, Vector<JS::NonnullGCPtr<Promise>> const& promises, Function<void(Vector<JS::Value> const&)> success_steps, Function<void(JS::Value)> failure_steps); void wait_for_all(JS::Realm&, Vector<JS::NonnullGCPtr<Promise>> const& promises, Function<void(Vector<JS::Value> const&)> success_steps, Function<void(JS::Value)> failure_steps);
// Non-spec, convenience method. // Non-spec, convenience method.
JS::NonnullGCPtr<JS::Promise> create_rejected_promise_from_exception(JS::Realm&, Exception); JS::NonnullGCPtr<Promise> create_rejected_promise_from_exception(JS::Realm&, Exception);
} }