LibWeb+IDLGenerators: Support nullable union types
This commit is contained in:
parent
500ca417ce
commit
cfd795f907
39 changed files with 146 additions and 128 deletions
|
|
@ -211,7 +211,7 @@ void Animation::set_timeline(GC::Ptr<AnimationTimeline> new_timeline)
|
|||
}
|
||||
|
||||
// https://drafts.csswg.org/web-animations-2/#validating-a-css-numberish-time
|
||||
WebIDL::ExceptionOr<Optional<TimeValue>> Animation::validate_a_css_numberish_time(Optional<CSS::CSSNumberish> const& time) const
|
||||
WebIDL::ExceptionOr<Optional<TimeValue>> Animation::validate_a_css_numberish_time(NullableCSSNumberish const& time) const
|
||||
{
|
||||
// The procedure to validate a CSSNumberish time for an input value of time is based on the first condition that matches:
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ WebIDL::ExceptionOr<Optional<TimeValue>> Animation::validate_a_css_numberish_tim
|
|||
m_timeline && m_timeline->is_progress_based() &&
|
||||
|
||||
// time is not a CSSNumeric value with percent units:
|
||||
(!time.has_value() || !time->has<GC::Root<CSS::CSSNumericValue>>() || !time->get<GC::Root<CSS::CSSNumericValue>>()->type().matches_percentage())) {
|
||||
(!time.has<GC::Root<CSS::CSSNumericValue>>() || !time.get<GC::Root<CSS::CSSNumericValue>>()->type().matches_percentage())) {
|
||||
// throw a TypeError.
|
||||
// return false;
|
||||
return WebIDL::SimpleException {
|
||||
|
|
@ -236,14 +236,14 @@ WebIDL::ExceptionOr<Optional<TimeValue>> Animation::validate_a_css_numberish_tim
|
|||
(!m_timeline || !m_timeline->is_progress_based()) &&
|
||||
|
||||
// time is a CSSNumericValue, and
|
||||
time.has_value() && time->has<GC::Root<CSS::CSSNumericValue>>() &&
|
||||
time.has<GC::Root<CSS::CSSNumericValue>>() &&
|
||||
|
||||
// the units of time are not duration units:
|
||||
!time->get<GC::Root<CSS::CSSNumericValue>>()->type().matches_time({}) &&
|
||||
!time.get<GC::Root<CSS::CSSNumericValue>>()->type().matches_time({}) &&
|
||||
|
||||
// AD-HOC: While it's not mentioned in the spec WPT also expects us to support CSSNumericValue number value, see
|
||||
// https://github.com/w3c/csswg-drafts/issues/13196
|
||||
!time->get<GC::Root<CSS::CSSNumericValue>>()->type().matches_number({})) {
|
||||
!time.get<GC::Root<CSS::CSSNumericValue>>()->type().matches_number({})) {
|
||||
// throw a TypeError.
|
||||
// return false.
|
||||
return WebIDL::SimpleException {
|
||||
|
|
@ -257,19 +257,19 @@ WebIDL::ExceptionOr<Optional<TimeValue>> Animation::validate_a_css_numberish_tim
|
|||
|
||||
// AD-HOC: The spec doesn't say when we should absolutize the validated value so we do it here and return the
|
||||
// absolutized value instead of a boolean
|
||||
if (!time.has_value())
|
||||
if (time.has<Empty>())
|
||||
return OptionalNone {};
|
||||
|
||||
// FIXME: Figure out which element we should use for this, for now we just use the document element of the current
|
||||
// window
|
||||
return TimeValue::from_css_numberish(time.value(), DOM::AbstractElement { *as<HTML::Window>(realm().global_object()).associated_document().document_element() });
|
||||
return TimeValue::from_css_numberish(time.downcast<double, GC::Root<CSS::CSSNumericValue>>(), DOM::AbstractElement { *as<HTML::Window>(realm().global_object()).associated_document().document_element() });
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animation-starttime
|
||||
// https://www.w3.org/TR/web-animations-1/#set-the-start-time
|
||||
WebIDL::ExceptionOr<void> Animation::set_start_time_for_bindings(Optional<CSS::CSSNumberish> const& raw_new_start_time)
|
||||
WebIDL::ExceptionOr<void> Animation::set_start_time_for_bindings(NullableCSSNumberish const& raw_new_start_time)
|
||||
{
|
||||
// Setting this attribute updates the start time using the procedure to set the start time of this object to the new
|
||||
// value.
|
||||
|
|
@ -400,7 +400,7 @@ Optional<TimeValue> Animation::current_time() const
|
|||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animation-set-the-current-time
|
||||
WebIDL::ExceptionOr<void> Animation::set_current_time_for_bindings(Optional<CSS::CSSNumberish> const& raw_seek_time)
|
||||
WebIDL::ExceptionOr<void> Animation::set_current_time_for_bindings(NullableCSSNumberish const& raw_seek_time)
|
||||
{
|
||||
// AD-HOC: We validate here instead of within silently_set_current_time so we have access to the `TimeValue`
|
||||
// value within this function.
|
||||
|
|
@ -655,7 +655,7 @@ void Animation::cancel(ShouldInvalidate should_invalidate)
|
|||
// not associated with an active timeline, let timeline time be an unresolved time value.
|
||||
// 9. Set cancelEvent’s timelineTime to timeline time. If timeline time is unresolved, set it to null.
|
||||
AnimationPlaybackEventInit init;
|
||||
init.timeline_time = m_timeline && !m_timeline->is_inactive() ? m_timeline->current_time().map([&](auto const& value) { return value.as_css_numberish(realm); }) : Optional<CSS::CSSNumberish> {};
|
||||
init.timeline_time = m_timeline && !m_timeline->is_inactive() ? NullableCSSNumberish { m_timeline->current_time()->as_css_numberish(realm) } : NullableCSSNumberish { Empty {} };
|
||||
auto cancel_event = AnimationPlaybackEvent::create(realm, HTML::EventNames::cancel, init);
|
||||
|
||||
// 10. If animation has a document for timing, then append cancelEvent to its document for timing's pending
|
||||
|
|
@ -1329,7 +1329,7 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
|
|||
AnimationPlaybackEventInit init;
|
||||
init.current_time = current_time()->as_css_numberish(realm);
|
||||
if (m_timeline && !m_timeline->is_inactive())
|
||||
init.timeline_time = m_timeline->current_time().map([&](auto const& value) { return value.as_css_numberish(realm); });
|
||||
init.timeline_time = m_timeline->current_time()->as_css_numberish(realm);
|
||||
|
||||
auto finish_event = AnimationPlaybackEvent::create(realm, HTML::EventNames::finish, init);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public:
|
|||
return NullableCSSNumberish::from_optional_css_numberish_time(realm(), start_time());
|
||||
}
|
||||
Optional<TimeValue> start_time() const { return m_start_time; }
|
||||
WebIDL::ExceptionOr<void> set_start_time_for_bindings(Optional<CSS::CSSNumberish> const&);
|
||||
WebIDL::ExceptionOr<void> set_start_time_for_bindings(NullableCSSNumberish const&);
|
||||
|
||||
void calculate_auto_aligned_start_time();
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ public:
|
|||
return NullableCSSNumberish::from_optional_css_numberish_time(realm(), current_time());
|
||||
}
|
||||
Optional<TimeValue> current_time() const;
|
||||
WebIDL::ExceptionOr<void> set_current_time_for_bindings(Optional<CSS::CSSNumberish> const&);
|
||||
WebIDL::ExceptionOr<void> set_current_time_for_bindings(NullableCSSNumberish const&);
|
||||
|
||||
double playback_rate() const { return m_playback_rate; }
|
||||
WebIDL::ExceptionOr<void> set_playback_rate(double value);
|
||||
|
|
@ -163,7 +163,7 @@ private:
|
|||
|
||||
double effective_playback_rate() const;
|
||||
|
||||
WebIDL::ExceptionOr<Optional<TimeValue>> validate_a_css_numberish_time(Optional<CSS::CSSNumberish> const&) const;
|
||||
WebIDL::ExceptionOr<Optional<TimeValue>> validate_a_css_numberish_time(NullableCSSNumberish const&) const;
|
||||
|
||||
void apply_any_pending_playback_rate();
|
||||
WebIDL::ExceptionOr<void> silently_set_current_time(Optional<TimeValue>);
|
||||
|
|
|
|||
|
|
@ -25,11 +25,10 @@ WebIDL::ExceptionOr<GC::Ref<AnimationPlaybackEvent>> AnimationPlaybackEvent::con
|
|||
return create(realm, type, event_init);
|
||||
}
|
||||
|
||||
AnimationPlaybackEvent::CSSNumberishInternal AnimationPlaybackEvent::to_numberish_internal(Optional<CSS::CSSNumberish> const& numberish_root)
|
||||
AnimationPlaybackEvent::CSSNumberishInternal AnimationPlaybackEvent::to_numberish_internal(NullableCSSNumberish const& numberish_root)
|
||||
{
|
||||
if (!numberish_root.has_value())
|
||||
return Empty {};
|
||||
return numberish_root->visit(
|
||||
return numberish_root.visit(
|
||||
[](Empty) -> CSSNumberishInternal { return Empty {}; },
|
||||
[](GC::Root<CSS::CSSNumericValue> const& root) -> CSSNumberishInternal { return GC::Ref { *root }; },
|
||||
[](auto const& other) -> CSSNumberishInternal { return other; });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ namespace Web::Animations {
|
|||
|
||||
// https://www.w3.org/TR/web-animations-1/#dictdef-animationplaybackeventinit
|
||||
struct AnimationPlaybackEventInit : public DOM::EventInit {
|
||||
Optional<CSS::CSSNumberish> current_time;
|
||||
Optional<CSS::CSSNumberish> timeline_time;
|
||||
NullableCSSNumberish current_time { Empty {} };
|
||||
NullableCSSNumberish timeline_time { Empty {} };
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#animationplaybackevent
|
||||
|
|
@ -40,7 +40,7 @@ private:
|
|||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
using CSSNumberishInternal = Variant<Empty, double, GC::Ref<CSS::CSSNumericValue>>;
|
||||
static CSSNumberishInternal to_numberish_internal(Optional<CSS::CSSNumberish> const&);
|
||||
static CSSNumberishInternal to_numberish_internal(NullableCSSNumberish const&);
|
||||
static NullableCSSNumberish to_nullable_numberish(CSSNumberishInternal const&);
|
||||
|
||||
// https://drafts.csswg.org/web-animations-2/#dom-animationplaybackevent-currenttime
|
||||
|
|
|
|||
|
|
@ -74,9 +74,7 @@ struct TimeValue {
|
|||
CSS::CSSNumberish as_css_numberish(JS::Realm& realm) const;
|
||||
};
|
||||
|
||||
// FIXME: This struct is required since our IDL generator requires us to return nullable union types as
|
||||
// Variant<Empty, Ts...> rather than Optional<Variant<Ts...>> (although setters are forced to be
|
||||
// Optional<Variant<Ts...>>)
|
||||
// Nullable CSSNumberish is Variant<double, GC::Root<CSSNumericValue>, Empty> where Empty represents null.
|
||||
struct NullableCSSNumberish : FlattenVariant<Variant<Empty>, CSS::CSSNumberish> {
|
||||
using Variant::Variant;
|
||||
|
||||
|
|
|
|||
|
|
@ -5944,8 +5944,8 @@ void Document::remove_replaced_animations()
|
|||
// - Set removeEvent’s timelineTime attribute to the current time of the timeline with which animation is
|
||||
// associated.
|
||||
Animations::AnimationPlaybackEventInit init;
|
||||
init.current_time = animation->current_time().map([&](auto const& value) { return value.as_css_numberish(realm()); });
|
||||
init.timeline_time = animation->timeline()->current_time().map([&](auto const& value) { return value.as_css_numberish(realm()); });
|
||||
init.current_time = animation->current_time().has_value() ? Animations::NullableCSSNumberish { animation->current_time()->as_css_numberish(realm()) } : Animations::NullableCSSNumberish { Empty {} };
|
||||
init.timeline_time = animation->timeline()->current_time().has_value() ? Animations::NullableCSSNumberish { animation->timeline()->current_time()->as_css_numberish(realm()) } : Animations::NullableCSSNumberish { Empty {} };
|
||||
auto remove_event = Animations::AnimationPlaybackEvent::create(realm(), HTML::EventNames::remove, init);
|
||||
|
||||
// - If animation has a document for timing, then append removeEvent to its document for timing's pending
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Web::Fetch {
|
|||
|
||||
// https://fetch.spec.whatwg.org/#bodyinit
|
||||
using BodyInit = Variant<GC::Root<Streams::ReadableStream>, GC::Root<FileAPI::Blob>, GC::Root<WebIDL::BufferSource>, GC::Root<XHR::FormData>, GC::Root<DOMURL::URLSearchParams>, String>;
|
||||
using NullableBodyInit = Variant<GC::Root<Streams::ReadableStream>, GC::Root<FileAPI::Blob>, GC::Root<WebIDL::BufferSource>, GC::Root<XHR::FormData>, GC::Root<DOMURL::URLSearchParams>, String, Empty>;
|
||||
|
||||
using BodyInitOrReadableBytes = Variant<GC::Root<Streams::ReadableStream>, GC::Root<FileAPI::Blob>, GC::Root<WebIDL::BufferSource>, GC::Root<XHR::FormData>, GC::Root<DOMURL::URLSearchParams>, String, ReadonlyBytes>;
|
||||
WEB_API Infrastructure::BodyWithType safely_extract_body(JS::Realm&, BodyInitOrReadableBytes const&);
|
||||
|
|
|
|||
|
|
@ -449,16 +449,16 @@ WebIDL::ExceptionOr<GC::Ref<Request>> Request::construct_impl(JS::Realm& realm,
|
|||
input_body = input.get<GC::Root<Request>>()->request()->body();
|
||||
|
||||
// 35. If either init["body"] exists and is non-null or inputBody is non-null, and request’s method is `GET` or `HEAD`, then throw a TypeError.
|
||||
if (((init.body.has_value() && (*init.body).has_value()) || (input_body.has_value() && !input_body.value().has<Empty>())) && request->method().is_one_of("GET"sv, "HEAD"sv))
|
||||
if (((init.body.has_value() && !init.body->has<Empty>()) || (input_body.has_value() && !input_body.value().has<Empty>())) && request->method().is_one_of("GET"sv, "HEAD"sv))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must not be GET or HEAD when body is provided"sv };
|
||||
|
||||
// 36. Let initBody be null.
|
||||
Optional<Infrastructure::Request::BodyType> init_body;
|
||||
|
||||
// 37. If init["body"] exists and is non-null, then:
|
||||
if (init.body.has_value() && (*init.body).has_value()) {
|
||||
// 1. Let bodyWithType be the result of extracting init["body"], with keepalive set to request’s keepalive.
|
||||
auto body_with_type = TRY(extract_body(realm, (*init.body).value(), request->keepalive()));
|
||||
if (init.body.has_value() && !init.body->has<Empty>()) {
|
||||
// 1. Let bodyWithType be the result of extracting init["body"], with keepalive set to request's keepalive.
|
||||
auto body_with_type = TRY(extract_body(realm, init.body->downcast<GC::Root<Streams::ReadableStream>, GC::Root<FileAPI::Blob>, GC::Root<WebIDL::BufferSource>, GC::Root<XHR::FormData>, GC::Root<DOMURL::URLSearchParams>, String>(), request->keepalive()));
|
||||
|
||||
// 2. Set initBody to bodyWithType’s body.
|
||||
init_body = body_with_type.body;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ using RequestInfo = Variant<GC::Root<Request>, String>;
|
|||
struct RequestInit {
|
||||
Optional<String> method;
|
||||
Optional<HeadersInit> headers;
|
||||
Optional<Optional<BodyInit>> body;
|
||||
Optional<NullableBodyInit> body;
|
||||
Optional<String> referrer;
|
||||
Optional<Bindings::ReferrerPolicy> referrer_policy;
|
||||
Optional<Bindings::RequestMode> mode;
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ WebIDL::ExceptionOr<void> Response::initialize_response(ResponseInit const& init
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#dom-response
|
||||
WebIDL::ExceptionOr<GC::Ref<Response>> Response::construct_impl(JS::Realm& realm, Optional<BodyInit> const& body, ResponseInit const& init)
|
||||
WebIDL::ExceptionOr<GC::Ref<Response>> Response::construct_impl(JS::Realm& realm, NullableBodyInit const& body, ResponseInit const& init)
|
||||
{
|
||||
auto& vm = realm.vm();
|
||||
|
||||
|
|
@ -155,8 +155,8 @@ WebIDL::ExceptionOr<GC::Ref<Response>> Response::construct_impl(JS::Realm& realm
|
|||
Optional<Infrastructure::BodyWithType> body_with_type;
|
||||
|
||||
// 4. If body is non-null, then set bodyWithType to the result of extracting body.
|
||||
if (body.has_value())
|
||||
body_with_type = TRY(extract_body(realm, *body));
|
||||
if (!body.has<Empty>())
|
||||
body_with_type = TRY(extract_body(realm, body.downcast<GC::Root<Streams::ReadableStream>, GC::Root<FileAPI::Blob>, GC::Root<WebIDL::BufferSource>, GC::Root<XHR::FormData>, GC::Root<DOMURL::URLSearchParams>, String>()));
|
||||
|
||||
// 5. Perform initialize a response given this, init, and bodyWithType.
|
||||
TRY(response_object->initialize_response(init, body_with_type));
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class Response final
|
|||
|
||||
public:
|
||||
[[nodiscard]] static GC::Ref<Response> create(JS::Realm&, GC::Ref<Infrastructure::Response>, Headers::Guard);
|
||||
static WebIDL::ExceptionOr<GC::Ref<Response>> construct_impl(JS::Realm&, Optional<BodyInit> const& body = {}, ResponseInit const& init = {});
|
||||
static WebIDL::ExceptionOr<GC::Ref<Response>> construct_impl(JS::Realm&, NullableBodyInit const& body = { Empty {} }, ResponseInit const& init = {});
|
||||
|
||||
virtual ~Response() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ GC::Ptr<DOM::ShadowRoot> ElementInternals::shadow_root() const
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/custom-elements.html#dom-elementinternals-setformvalue
|
||||
WebIDL::ExceptionOr<void> ElementInternals::set_form_value(Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>> value, Optional<Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>>> state)
|
||||
WebIDL::ExceptionOr<void> ElementInternals::set_form_value(Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>, Empty> value, Optional<Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>, Empty>> state)
|
||||
{
|
||||
// 1. Let element be this's target element.
|
||||
auto element = m_target_element;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public:
|
|||
|
||||
GC::Ptr<DOM::ShadowRoot> shadow_root() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_form_value(Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>> value, Optional<Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>>> state);
|
||||
WebIDL::ExceptionOr<void> set_form_value(Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>, Empty> value, Optional<Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>, Empty>> state);
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ptr<HTMLFormElement>> form() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -849,7 +849,7 @@ GC::Ptr<DOM::NodeList> HTMLElement::labels()
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/interaction.html#dom-hidden
|
||||
Variant<bool, double, String> HTMLElement::hidden() const
|
||||
Variant<bool, double, String, Empty> HTMLElement::hidden() const
|
||||
{
|
||||
// 1. If the hidden attribute is in the hidden until found state, then return "until-found".
|
||||
auto const& hidden = get_attribute(HTML::AttributeNames::hidden);
|
||||
|
|
@ -862,7 +862,7 @@ Variant<bool, double, String> HTMLElement::hidden() const
|
|||
return false;
|
||||
}
|
||||
|
||||
void HTMLElement::set_hidden(Variant<bool, double, String> const& given_value)
|
||||
void HTMLElement::set_hidden(Variant<bool, double, String, Empty> const& given_value)
|
||||
{
|
||||
// 1. If the given value is a string that is an ASCII case-insensitive match for "until-found", then set the hidden attribute to "until-found".
|
||||
if (given_value.has<String>()) {
|
||||
|
|
@ -876,11 +876,6 @@ void HTMLElement::set_hidden(Variant<bool, double, String> const& given_value)
|
|||
remove_attribute(HTML::AttributeNames::hidden);
|
||||
return;
|
||||
}
|
||||
// 4. Otherwise, if the given value is null, then remove the hidden attribute.
|
||||
if (string.equals_ignoring_ascii_case("null"sv) || string.equals_ignoring_ascii_case("undefined"sv)) {
|
||||
remove_attribute(HTML::AttributeNames::hidden);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 2. Otherwise, if the given value is false, then remove the hidden attribute.
|
||||
else if (given_value.has<bool>()) {
|
||||
|
|
@ -898,6 +893,11 @@ void HTMLElement::set_hidden(Variant<bool, double, String> const& given_value)
|
|||
return;
|
||||
}
|
||||
}
|
||||
// 4. Otherwise, if the given value is null, then remove the hidden attribute.
|
||||
else if (given_value.has<Empty>()) {
|
||||
remove_attribute(HTML::AttributeNames::hidden);
|
||||
return;
|
||||
}
|
||||
// 7. Otherwise, set the hidden attribute to the empty string.
|
||||
set_attribute_value(HTML::AttributeNames::hidden, ""_string);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,8 +108,8 @@ public:
|
|||
GC::Ptr<Element> offset_parent() const;
|
||||
GC::Ptr<Element> scroll_parent() const;
|
||||
|
||||
Variant<bool, double, String> hidden() const;
|
||||
void set_hidden(Variant<bool, double, String> const&);
|
||||
Variant<bool, double, String, Empty> hidden() const;
|
||||
void set_hidden(Variant<bool, double, String, Empty> const&);
|
||||
|
||||
void click();
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ WebIDL::ExceptionOr<void> HTMLOptionsCollection::set_value_of_indexed_property(u
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-add
|
||||
WebIDL::ExceptionOr<void> HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before)
|
||||
WebIDL::ExceptionOr<void> HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement element, NullableHTMLElementOrElementIndex before)
|
||||
{
|
||||
auto resolved_element = element.visit(
|
||||
[](auto& e) -> GC::Root<HTMLElement> {
|
||||
|
|
@ -127,8 +127,8 @@ WebIDL::ExceptionOr<void> HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement
|
|||
});
|
||||
|
||||
GC::Ptr<DOM::Node> before_element;
|
||||
if (before.has_value() && before->has<GC::Root<HTMLElement>>())
|
||||
before_element = before->get<GC::Root<HTMLElement>>().ptr();
|
||||
if (before.has<GC::Root<HTMLElement>>())
|
||||
before_element = before.get<GC::Root<HTMLElement>>().ptr();
|
||||
|
||||
// 1. If element is an ancestor of the select element on which the HTMLOptionsCollection is rooted, then throw a "HierarchyRequestError" DOMException.
|
||||
if (resolved_element->is_ancestor_of(root()))
|
||||
|
|
@ -147,8 +147,8 @@ WebIDL::ExceptionOr<void> HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement
|
|||
|
||||
if (before_element)
|
||||
reference = move(before_element);
|
||||
else if (before.has_value() && before->has<i32>())
|
||||
reference = item(before->get<i32>());
|
||||
else if (before.has<i32>())
|
||||
reference = item(before.get<i32>());
|
||||
|
||||
// 5. If reference is not null, let parent be the parent node of reference. Otherwise, let parent be the select element on which the HTMLOptionsCollection is rooted.
|
||||
DOM::Node* parent = reference ? reference->parent() : root().ptr();
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ namespace Web::HTML {
|
|||
|
||||
using HTMLOptionOrOptGroupElement = Variant<GC::Root<HTMLOptionElement>, GC::Root<HTMLOptGroupElement>>;
|
||||
using HTMLElementOrElementIndex = Variant<GC::Root<HTMLElement>, i32>;
|
||||
using NullableHTMLElementOrElementIndex = Variant<GC::Root<HTMLElement>, i32, Empty>;
|
||||
|
||||
class HTMLOptionsCollection final : public DOM::HTMLCollection {
|
||||
WEB_PLATFORM_OBJECT(HTMLOptionsCollection, DOM::HTMLCollection);
|
||||
|
|
@ -28,7 +29,7 @@ public:
|
|||
|
||||
WebIDL::ExceptionOr<void> set_length(WebIDL::UnsignedLong);
|
||||
|
||||
WebIDL::ExceptionOr<void> add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before = {});
|
||||
WebIDL::ExceptionOr<void> add(HTMLOptionOrOptGroupElement element, NullableHTMLElementOrElementIndex before = { Empty {} });
|
||||
|
||||
void remove(WebIDL::Long);
|
||||
|
||||
|
|
|
|||
|
|
@ -770,14 +770,21 @@ Variant<GC::Root<TrustedTypes::TrustedScript>, Utf16String, Empty> HTMLScriptEle
|
|||
}
|
||||
|
||||
// https://w3c.github.io/trusted-types/dist/spec/#the-textContent-idl-attribute
|
||||
WebIDL::ExceptionOr<void> HTMLScriptElement::set_text_content(TrustedTypes::TrustedScriptOrString text)
|
||||
WebIDL::ExceptionOr<void> HTMLScriptElement::set_text_content(TrustedTypes::NullableTrustedScriptOrString text)
|
||||
{
|
||||
// NOTE: We still require this from the base implementation.
|
||||
// https://dom.spec.whatwg.org/#dom-node-textcontent
|
||||
// The textContent setter steps are to, if the given value is null, act as if it was the empty string instead, and then run set text content with this and the given value.
|
||||
TrustedTypes::TrustedScriptOrString non_null_text = text.has<Empty>()
|
||||
? ""_utf16
|
||||
: text.downcast<TrustedTypes::TrustedScriptOrString>();
|
||||
|
||||
// 1. Let value be the result of calling Get Trusted Type compliant string with
|
||||
// TrustedScript, this’s relevant global object, the given value, HTMLScriptElement textContent, and script.
|
||||
// TrustedScript, this's relevant global object, the given value, HTMLScriptElement textContent, and script.
|
||||
auto const value = TRY(TrustedTypes::get_trusted_type_compliant_string(
|
||||
TrustedTypes::TrustedTypeName::TrustedScript,
|
||||
HTML::relevant_global_object(*this),
|
||||
text,
|
||||
non_null_text,
|
||||
TrustedTypes::InjectionSink::HTMLScriptElement_textContent,
|
||||
TrustedTypes::Script.to_string()));
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public:
|
|||
WebIDL::ExceptionOr<void> set_src(TrustedTypes::TrustedScriptURLOrString);
|
||||
|
||||
Variant<GC::Root<TrustedTypes::TrustedScript>, Utf16String, Empty> text_content() const;
|
||||
WebIDL::ExceptionOr<void> set_text_content(TrustedTypes::TrustedScriptOrString);
|
||||
WebIDL::ExceptionOr<void> set_text_content(TrustedTypes::NullableTrustedScriptOrString);
|
||||
|
||||
TrustedTypes::TrustedScriptOrString inner_text();
|
||||
WebIDL::ExceptionOr<void> set_inner_text(TrustedTypes::TrustedScriptOrString);
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ HTMLOptionElement* HTMLSelectElement::named_item(FlyString const& name)
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-select-add
|
||||
WebIDL::ExceptionOr<void> HTMLSelectElement::add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before)
|
||||
WebIDL::ExceptionOr<void> HTMLSelectElement::add(HTMLOptionOrOptGroupElement element, NullableHTMLElementOrElementIndex before)
|
||||
{
|
||||
// Similarly, the add(element, before) method must act like its namesake method on that same options collection.
|
||||
TRY(const_cast<HTMLOptionsCollection&>(*options()).add(move(element), move(before)));
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public:
|
|||
HTMLOptionElement* item(WebIDL::UnsignedLong index);
|
||||
virtual Optional<JS::Value> item_value(size_t index) const override;
|
||||
HTMLOptionElement* named_item(FlyString const& name);
|
||||
WebIDL::ExceptionOr<void> add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before = {});
|
||||
WebIDL::ExceptionOr<void> add(HTMLOptionOrOptGroupElement element, NullableHTMLElementOrElementIndex before = { Empty {} });
|
||||
virtual WebIDL::ExceptionOr<void> set_value_of_indexed_property(u32, JS::Value) override;
|
||||
void remove();
|
||||
void remove(WebIDL::Long);
|
||||
|
|
|
|||
|
|
@ -27,12 +27,11 @@ WebIDL::ExceptionOr<GC::Ref<MessageEvent>> MessageEvent::construct_impl(JS::Real
|
|||
return create(realm, event_name, event_init);
|
||||
}
|
||||
|
||||
MessageEvent::MessageEventSourceInternal MessageEvent::to_message_event_source_internal(Optional<MessageEventSource> const& source)
|
||||
MessageEvent::MessageEventSourceInternal MessageEvent::to_message_event_source_internal(NullableMessageEventSource const& source)
|
||||
{
|
||||
if (!source.has_value())
|
||||
return Empty {};
|
||||
|
||||
return source->visit([](auto const& root) -> MessageEventSourceInternal { return GC::Ref { *root }; });
|
||||
return source.visit(
|
||||
[](Empty) -> MessageEventSourceInternal { return Empty {}; },
|
||||
[](auto const& root) -> MessageEventSourceInternal { return GC::Ref { *root }; });
|
||||
}
|
||||
|
||||
MessageEvent::MessageEvent(JS::Realm& realm, FlyString const& event_name, MessageEventInit const& event_init)
|
||||
|
|
@ -86,11 +85,11 @@ String MessageEvent::origin() const
|
|||
});
|
||||
}
|
||||
|
||||
MessageEvent::SourceResult MessageEvent::source() const
|
||||
NullableMessageEventSource MessageEvent::source() const
|
||||
{
|
||||
return m_source.visit(
|
||||
[](Empty) -> SourceResult { return Empty {}; },
|
||||
[](auto const& ref) -> SourceResult { return GC::Root { *ref }; });
|
||||
[](Empty) -> NullableMessageEventSource { return Empty {}; },
|
||||
[](auto const& ref) -> NullableMessageEventSource { return GC::Root { *ref }; });
|
||||
}
|
||||
|
||||
GC::Ref<JS::Object> MessageEvent::ports() const
|
||||
|
|
@ -107,7 +106,7 @@ GC::Ref<JS::Object> MessageEvent::ports() const
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/comms.html#dom-messageevent-initmessageevent
|
||||
void MessageEvent::init_message_event(String const& type, bool bubbles, bool cancelable, JS::Value data, String const& origin, String const& last_event_id, Optional<MessageEventSource> source, Vector<GC::Root<MessagePort>> const& ports)
|
||||
void MessageEvent::init_message_event(String const& type, bool bubbles, bool cancelable, JS::Value data, String const& origin, String const& last_event_id, NullableMessageEventSource source, Vector<GC::Root<MessagePort>> const& ports)
|
||||
{
|
||||
// The initMessageEvent(type, bubbles, cancelable, data, origin, lastEventId, source, ports) method must initialize the event in a
|
||||
// manner analogous to the similarly-named initEvent() method.
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ namespace Web::HTML {
|
|||
// FIXME: Include ServiceWorker
|
||||
// https://html.spec.whatwg.org/multipage/comms.html#messageeventsource
|
||||
using MessageEventSource = Variant<GC::Root<WindowProxy>, GC::Root<MessagePort>>;
|
||||
using NullableMessageEventSource = Variant<GC::Root<WindowProxy>, GC::Root<MessagePort>, Empty>;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/comms.html#messageeventinit
|
||||
struct MessageEventInit : public DOM::EventInit {
|
||||
JS::Value data { JS::js_null() };
|
||||
Variant<URL::Origin, String, Empty> origin {};
|
||||
String last_event_id {};
|
||||
Optional<MessageEventSource> source;
|
||||
NullableMessageEventSource source { Empty {} };
|
||||
Vector<GC::Root<MessagePort>> ports;
|
||||
};
|
||||
|
||||
|
|
@ -44,19 +45,18 @@ public:
|
|||
String const& last_event_id() const { return m_last_event_id; }
|
||||
GC::Ref<JS::Object> ports() const;
|
||||
|
||||
using SourceResult = Variant<Empty, GC::Root<WindowProxy>, GC::Root<MessagePort>>;
|
||||
SourceResult source() const;
|
||||
NullableMessageEventSource source() const;
|
||||
|
||||
virtual Optional<URL::Origin> extract_an_origin() const override;
|
||||
|
||||
void init_message_event(String const& type, bool bubbles, bool cancelable, JS::Value data, String const& origin, String const& last_event_id, Optional<MessageEventSource> source, Vector<GC::Root<MessagePort>> const& ports);
|
||||
void init_message_event(String const& type, bool bubbles, bool cancelable, JS::Value data, String const& origin, String const& last_event_id, NullableMessageEventSource source, Vector<GC::Root<MessagePort>> const& ports);
|
||||
|
||||
private:
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
using MessageEventSourceInternal = Variant<Empty, GC::Ref<WindowProxy>, GC::Ref<MessagePort>>;
|
||||
static MessageEventSourceInternal to_message_event_source_internal(Optional<MessageEventSource> const&);
|
||||
static MessageEventSourceInternal to_message_event_source_internal(NullableMessageEventSource const&);
|
||||
|
||||
JS::Value m_data;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
namespace Web::HTML {
|
||||
|
||||
// https://w3c.github.io/beacon/#sendbeacon-method
|
||||
WebIDL::ExceptionOr<bool> NavigatorBeaconPartial::send_beacon(String const& url, Optional<Fetch::BodyInit> const& data)
|
||||
WebIDL::ExceptionOr<bool> NavigatorBeaconPartial::send_beacon(String const& url, Fetch::NullableBodyInit const& data)
|
||||
{
|
||||
auto& navigator = as<Navigator>(*this);
|
||||
auto& realm = navigator.realm();
|
||||
|
|
@ -46,9 +46,9 @@ WebIDL::ExceptionOr<bool> NavigatorBeaconPartial::send_beacon(String const& url,
|
|||
|
||||
// 6. If data is not null:
|
||||
GC::Ptr<Fetch::Infrastructure::Body> transmitted_data;
|
||||
if (data.has_value()) {
|
||||
if (!data.has<Empty>()) {
|
||||
// 6.1 Set transmittedData and contentType to the result of extracting data's byte stream with the keepalive flag set.
|
||||
auto body_with_type = TRY(Fetch::extract_body(realm, data.value(), true));
|
||||
auto body_with_type = TRY(Fetch::extract_body(realm, data.downcast<GC::Root<Streams::ReadableStream>, GC::Root<FileAPI::Blob>, GC::Root<WebIDL::BufferSource>, GC::Root<XHR::FormData>, GC::Root<DOMURL::URLSearchParams>, String>(), true));
|
||||
transmitted_data = body_with_type.body;
|
||||
auto& content_type = body_with_type.type;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Web::HTML {
|
|||
|
||||
class NavigatorBeaconPartial {
|
||||
public:
|
||||
WebIDL::ExceptionOr<bool> send_beacon(String const& url, Optional<Fetch::BodyInit> const& data = {});
|
||||
WebIDL::ExceptionOr<bool> send_beacon(String const& url, Fetch::NullableBodyInit const& data = { Empty {} });
|
||||
|
||||
private:
|
||||
virtual ~NavigatorBeaconPartial() = default;
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ WebIDL::ExceptionOr<GC::Ref<SharedWorker>> SharedWorker::construct_impl(JS::Real
|
|||
MessageEventInit init;
|
||||
init.data = JS::PrimitiveString::create(realm.vm(), String {});
|
||||
init.ports.append(inside_port);
|
||||
init.source = inside_port;
|
||||
init.source = NullableMessageEventSource { inside_port };
|
||||
|
||||
worker_global_scope->dispatch_event(MessageEvent::create(realm, EventNames::connect, init));
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -26,15 +26,11 @@ WebIDL::ExceptionOr<GC::Ref<TrackEvent>> TrackEvent::construct_impl(JS::Realm& r
|
|||
return create(realm, event_name, move(event_init));
|
||||
}
|
||||
|
||||
TrackEvent::TrackTypeInternal TrackEvent::to_track_type_internal(TrackEventInit::TrackType const& track_type)
|
||||
TrackEvent::TrackTypeInternal TrackEvent::to_track_type_internal(NullableTrackType const& track_type)
|
||||
{
|
||||
if (!track_type.has_value())
|
||||
return Empty {};
|
||||
|
||||
return track_type->visit(
|
||||
[](GC::Root<VideoTrack> const& root) -> TrackTypeInternal { return GC::Ref { *root }; },
|
||||
[](GC::Root<AudioTrack> const& root) -> TrackTypeInternal { return GC::Ref { *root }; },
|
||||
[](GC::Root<TextTrack> const& root) -> TrackTypeInternal { return GC::Ref { *root }; });
|
||||
return track_type.visit(
|
||||
[](Empty) -> TrackTypeInternal { return Empty {}; },
|
||||
[](auto const& root) -> TrackTypeInternal { return GC::Ref { *root }; });
|
||||
}
|
||||
|
||||
TrackEvent::TrackEvent(JS::Realm& realm, FlyString const& event_name, TrackEventInit event_init)
|
||||
|
|
@ -57,11 +53,11 @@ void TrackEvent::visit_edges(Visitor& visitor)
|
|||
[&](auto const& ref) { visitor.visit(ref); });
|
||||
}
|
||||
|
||||
TrackEvent::TrackReturnType TrackEvent::track() const
|
||||
NullableTrackType TrackEvent::track() const
|
||||
{
|
||||
return m_track.visit(
|
||||
[](Empty) -> TrackReturnType { return Empty {}; },
|
||||
[](auto const& ref) -> TrackReturnType { return GC::Root { *ref }; });
|
||||
[](Empty) -> NullableTrackType { return Empty {}; },
|
||||
[](auto const& ref) -> NullableTrackType { return GC::Root { *ref }; });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,10 @@
|
|||
|
||||
namespace Web::HTML {
|
||||
|
||||
using NullableTrackType = Variant<GC::Root<VideoTrack>, GC::Root<AudioTrack>, GC::Root<TextTrack>, Empty>;
|
||||
|
||||
struct TrackEventInit : public DOM::EventInit {
|
||||
using TrackType = Optional<Variant<GC::Root<VideoTrack>, GC::Root<AudioTrack>, GC::Root<TextTrack>>>;
|
||||
TrackType track;
|
||||
NullableTrackType track { Empty {} };
|
||||
};
|
||||
|
||||
class TrackEvent : public DOM::Event {
|
||||
|
|
@ -29,8 +30,7 @@ public:
|
|||
static WebIDL::ExceptionOr<GC::Ref<TrackEvent>> construct_impl(JS::Realm&, FlyString const& event_name, TrackEventInit);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-trackevent-track
|
||||
using TrackReturnType = Variant<Empty, GC::Root<VideoTrack>, GC::Root<AudioTrack>, GC::Root<TextTrack>>;
|
||||
TrackReturnType track() const;
|
||||
NullableTrackType track() const;
|
||||
|
||||
private:
|
||||
TrackEvent(JS::Realm&, FlyString const& event_name, TrackEventInit event_init);
|
||||
|
|
@ -39,7 +39,7 @@ private:
|
|||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
using TrackTypeInternal = Variant<Empty, GC::Ref<VideoTrack>, GC::Ref<AudioTrack>, GC::Ref<TextTrack>>;
|
||||
static TrackTypeInternal to_track_type_internal(TrackEventInit::TrackType const&);
|
||||
static TrackTypeInternal to_track_type_internal(NullableTrackType const&);
|
||||
|
||||
TrackTypeInternal m_track;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -118,7 +118,10 @@ WebIDL::ExceptionOr<GC::Ref<IDBObjectStore>> IDBDatabase::create_object_store(St
|
|||
return WebIDL::TransactionInactiveError::create(realm, "Transaction is not active while creating object store"_utf16);
|
||||
|
||||
// 4. Let keyPath be options’s keyPath member if it is not undefined or null, or null otherwise.
|
||||
auto key_path = options.key_path;
|
||||
auto const& nullable_key_path = options.key_path;
|
||||
Optional<KeyPath> key_path;
|
||||
if (!nullable_key_path.has<Empty>())
|
||||
key_path = nullable_key_path.downcast<String, Vector<String>>();
|
||||
|
||||
// 5. If keyPath is not null and is not a valid key path, throw a "SyntaxError" DOMException.
|
||||
if (key_path.has_value() && !is_valid_key_path(key_path.value()))
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@
|
|||
namespace Web::IndexedDB {
|
||||
|
||||
using KeyPath = Variant<String, Vector<String>>;
|
||||
using NullableKeyPath = Variant<String, Vector<String>, Empty>;
|
||||
|
||||
// https://w3c.github.io/IndexedDB/#dictdef-idbobjectstoreparameters
|
||||
struct IDBObjectStoreParameters {
|
||||
Optional<KeyPath> key_path;
|
||||
NullableKeyPath key_path { Empty {} };
|
||||
bool auto_increment { false };
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ WebIDL::ExceptionOr<GC::Ref<IntersectionObserver>> IntersectionObserver::constru
|
|||
return realm.create<IntersectionObserver>(realm, callback, options.root, move(root_margin.value()), move(scroll_margin.value()), move(thresholds), move(delay), move(options.track_visibility));
|
||||
}
|
||||
|
||||
IntersectionObserver::IntersectionObserver(JS::Realm& realm, GC::Ptr<WebIDL::CallbackType> callback, Optional<Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>>> const& root, Vector<CSS::LengthPercentage> root_margin, Vector<CSS::LengthPercentage> scroll_margin, Vector<double>&& thresholds, double delay, bool track_visibility)
|
||||
IntersectionObserver::IntersectionObserver(JS::Realm& realm, GC::Ptr<WebIDL::CallbackType> callback, NullableIntersectionObserverRoot const& root, Vector<CSS::LengthPercentage> root_margin, Vector<CSS::LengthPercentage> scroll_margin, Vector<double>&& thresholds, double delay, bool track_visibility)
|
||||
: PlatformObject(realm)
|
||||
, m_callback(callback)
|
||||
, m_root_margin(root_margin)
|
||||
|
|
@ -93,7 +93,7 @@ IntersectionObserver::IntersectionObserver(JS::Realm& realm, GC::Ptr<WebIDL::Cal
|
|||
, m_delay(delay)
|
||||
, m_track_visibility(track_visibility)
|
||||
{
|
||||
m_root = root.has_value() ? root->visit([](auto& value) -> GC::Ptr<DOM::Node> { return *value; }) : nullptr;
|
||||
m_root = root.has<Empty>() ? nullptr : root.visit([](GC::Root<DOM::Element> const& value) -> GC::Ptr<DOM::Node> { return *value; }, [](GC::Root<DOM::Document> const& value) -> GC::Ptr<DOM::Node> { return *value; }, [](Empty) -> GC::Ptr<DOM::Node> { return nullptr; });
|
||||
intersection_root().visit([this](auto& node) {
|
||||
m_document = node->document();
|
||||
});
|
||||
|
|
@ -191,7 +191,7 @@ Vector<GC::Root<IntersectionObserverEntry>> IntersectionObserver::take_records()
|
|||
return queue;
|
||||
}
|
||||
|
||||
Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>, Empty> IntersectionObserver::root() const
|
||||
NullableIntersectionObserverRoot IntersectionObserver::root() const
|
||||
{
|
||||
if (!m_root)
|
||||
return Empty {};
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@
|
|||
|
||||
namespace Web::IntersectionObserver {
|
||||
|
||||
using NullableIntersectionObserverRoot = Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>, Empty>;
|
||||
|
||||
struct IntersectionObserverInit {
|
||||
Optional<Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>>> root;
|
||||
NullableIntersectionObserverRoot root { Empty {} };
|
||||
String root_margin { "0px"_string };
|
||||
String scroll_margin { "0px"_string };
|
||||
Variant<double, Vector<double>> threshold { 0 };
|
||||
|
|
@ -42,7 +44,7 @@ public:
|
|||
|
||||
Vector<GC::Ref<DOM::Element>> const& observation_targets() const { return m_observation_targets; }
|
||||
|
||||
Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>, Empty> root() const;
|
||||
NullableIntersectionObserverRoot root() const;
|
||||
String root_margin() const;
|
||||
String scroll_margin() const;
|
||||
Vector<CSS::LengthPercentage> const& scroll_margin_values() const { return m_scroll_margin; }
|
||||
|
|
@ -60,7 +62,7 @@ public:
|
|||
WebIDL::CallbackType& callback() { return *m_callback; }
|
||||
|
||||
private:
|
||||
explicit IntersectionObserver(JS::Realm&, GC::Ptr<WebIDL::CallbackType> callback, Optional<Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>>> const& root, Vector<CSS::LengthPercentage> root_margin, Vector<CSS::LengthPercentage> scroll_margin, Vector<double>&& thresholds, double debug, bool track_visibility);
|
||||
explicit IntersectionObserver(JS::Realm&, GC::Ptr<WebIDL::CallbackType> callback, NullableIntersectionObserverRoot const& root, Vector<CSS::LengthPercentage> root_margin, Vector<CSS::LengthPercentage> scroll_margin, Vector<double>&& thresholds, double debug, bool track_visibility);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(JS::Cell::Visitor&) override;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
namespace Web::TrustedTypes {
|
||||
|
||||
using TrustedScriptOrString = Variant<GC::Root<TrustedScript>, Utf16String>;
|
||||
using NullableTrustedScriptOrString = Variant<GC::Root<TrustedScript>, Utf16String, Empty>;
|
||||
|
||||
class TrustedScript final : public Bindings::PlatformObject {
|
||||
WEB_PLATFORM_OBJECT(TrustedScript, Bindings::PlatformObject);
|
||||
|
|
|
|||
|
|
@ -535,7 +535,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::open(String const& method, String cons
|
|||
}
|
||||
|
||||
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-send
|
||||
WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequestBodyInit> body)
|
||||
WebIDL::ExceptionOr<void> XMLHttpRequest::send(NullableDocumentOrXMLHttpRequestBodyInit body)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
auto& realm = *vm.current_realm();
|
||||
|
|
@ -550,23 +550,23 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
|||
|
||||
// 3. If this’s request method is `GET` or `HEAD`, then set body to null.
|
||||
if (m_request_method.is_one_of("GET"sv, "HEAD"sv))
|
||||
body = {};
|
||||
body = Empty {};
|
||||
|
||||
// 4. If body is not null, then:
|
||||
if (body.has_value()) {
|
||||
if (!body.has<Empty>()) {
|
||||
// 1. Let extractedContentType be null.
|
||||
Optional<ByteString> extracted_content_type;
|
||||
|
||||
// 2. If body is a Document, then set this’s request body to body, serialized, converted, and UTF-8 encoded.
|
||||
if (body->has<GC::Root<DOM::Document>>()) {
|
||||
auto string_serialized_document = TRY(body->get<GC::Root<DOM::Document>>().cell()->serialize_fragment(HTML::RequireWellFormed::No));
|
||||
if (body.has<GC::Root<DOM::Document>>()) {
|
||||
auto string_serialized_document = TRY(body.get<GC::Root<DOM::Document>>().cell()->serialize_fragment(HTML::RequireWellFormed::No));
|
||||
auto string_serialized_document_utf8 = string_serialized_document.to_utf8();
|
||||
m_request_body = Fetch::Infrastructure::byte_sequence_as_body(realm, string_serialized_document_utf8.bytes());
|
||||
}
|
||||
// 3. Otherwise:
|
||||
else {
|
||||
// 1. Let bodyWithType be the result of safely extracting body.
|
||||
auto body_with_type = Fetch::safely_extract_body(realm, body->downcast<Fetch::BodyInitOrReadableBytes>());
|
||||
auto body_with_type = Fetch::safely_extract_body(realm, body.downcast<Fetch::BodyInitOrReadableBytes>());
|
||||
|
||||
// 2. Set this’s request body to bodyWithType’s body.
|
||||
m_request_body = body_with_type.body;
|
||||
|
|
@ -581,7 +581,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
|||
// 5. If originalAuthorContentType is non-null, then:
|
||||
if (original_author_content_type.has_value()) {
|
||||
// 1. If body is a Document or a USVString, then:
|
||||
if (body->has<GC::Root<DOM::Document>>() || body->has<String>()) {
|
||||
if (body.has<GC::Root<DOM::Document>>() || body.has<String>()) {
|
||||
// 1. Let contentTypeRecord be the result of parsing originalAuthorContentType.
|
||||
auto content_type_record = MimeSniff::MimeType::parse(original_author_content_type.value());
|
||||
|
||||
|
|
@ -604,8 +604,8 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
|||
}
|
||||
// 6. Otherwise:
|
||||
else {
|
||||
if (body->has<GC::Root<DOM::Document>>()) {
|
||||
auto document = body->get<GC::Root<DOM::Document>>();
|
||||
if (body.has<GC::Root<DOM::Document>>()) {
|
||||
auto document = body.get<GC::Root<DOM::Document>>();
|
||||
|
||||
// NOTE: A document can only be an HTML document or XML document.
|
||||
// 1. If body is an HTML document, then set (`Content-Type`, `text/html;charset=UTF-8`) in this’s author request headers.
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace Web::XHR {
|
|||
|
||||
// https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit
|
||||
using DocumentOrXMLHttpRequestBodyInit = Variant<GC::Root<Web::DOM::Document>, GC::Root<Web::FileAPI::Blob>, GC::Root<WebIDL::BufferSource>, GC::Root<XHR::FormData>, GC::Root<Web::DOMURL::URLSearchParams>, AK::String>;
|
||||
using NullableDocumentOrXMLHttpRequestBodyInit = Variant<GC::Root<Web::DOM::Document>, GC::Root<Web::FileAPI::Blob>, GC::Root<WebIDL::BufferSource>, GC::Root<XHR::FormData>, GC::Root<Web::DOMURL::URLSearchParams>, AK::String, Empty>;
|
||||
|
||||
class XMLHttpRequest final : public XMLHttpRequestEventTarget {
|
||||
WEB_PLATFORM_OBJECT(XMLHttpRequest, XMLHttpRequestEventTarget);
|
||||
|
|
@ -59,7 +60,7 @@ public:
|
|||
|
||||
WebIDL::ExceptionOr<void> open(String const& method, String const& url);
|
||||
WebIDL::ExceptionOr<void> open(String const& method, String const& url, bool async, Optional<String> const& username = Optional<String> {}, Optional<String> const& password = Optional<String> {});
|
||||
WebIDL::ExceptionOr<void> send(Optional<DocumentOrXMLHttpRequestBodyInit> body);
|
||||
WebIDL::ExceptionOr<void> send(NullableDocumentOrXMLHttpRequestBodyInit body);
|
||||
|
||||
WebIDL::ExceptionOr<void> set_request_header(String const& name, String const& value);
|
||||
WebIDL::ExceptionOr<void> set_response_type(Bindings::XMLHttpRequestResponseType);
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ static ByteString union_type_to_variant(UnionType const& union_type, Interface c
|
|||
builder.append(cpp_type.name);
|
||||
}
|
||||
|
||||
if (union_type.includes_undefined())
|
||||
if (union_type.includes_undefined() || union_type.includes_nullable_type())
|
||||
builder.append(", Empty"sv);
|
||||
|
||||
builder.append('>');
|
||||
|
|
@ -1369,9 +1369,12 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
)~~~");
|
||||
}
|
||||
|
||||
// FIXME: 2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.
|
||||
// 2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.
|
||||
if (union_type.includes_nullable_type()) {
|
||||
// Implement me
|
||||
union_generator.append(R"~~~(
|
||||
if (@js_name@@js_suffix@.is_nullish())
|
||||
return Empty {};
|
||||
)~~~");
|
||||
} else if (dictionary_type) {
|
||||
// 4. If V is null or undefined, then
|
||||
// 4.1 If types includes a dictionary type, then return the result of converting V to that dictionary type.
|
||||
|
|
@ -1794,7 +1797,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
)~~~");
|
||||
} else {
|
||||
if (!optional_default_value.has_value()) {
|
||||
union_generator.set("nullish_or_undefined", union_type.is_nullable() ? "nullish" : "undefined");
|
||||
union_generator.set("nullish_or_undefined", "undefined");
|
||||
union_generator.append(R"~~~(
|
||||
Optional<@union_type@> @cpp_name@;
|
||||
if (!@js_name@@js_suffix@.is_@nullish_or_undefined@())
|
||||
|
|
@ -1802,11 +1805,17 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
)~~~");
|
||||
} else {
|
||||
if (optional_default_value == "null"sv) {
|
||||
union_generator.append(R"~~~(
|
||||
if (union_type.includes_nullable_type()) {
|
||||
union_generator.append(R"~~~(
|
||||
@union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? @union_type@ { Empty {} } : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
|
||||
)~~~");
|
||||
} else {
|
||||
union_generator.append(R"~~~(
|
||||
Optional<@union_type@> @cpp_name@;
|
||||
if (!@js_name@@js_suffix@.is_nullish())
|
||||
@cpp_name@ = TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
|
||||
)~~~");
|
||||
}
|
||||
} else if (optional_default_value == "\"\"") {
|
||||
union_generator.append(R"~~~(
|
||||
@union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? TRY(@js_name@@js_suffix@_to_variant(JS::Value(JS::PrimitiveString::create(vm, String {})))) : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
|
||||
|
|
@ -2182,8 +2191,8 @@ static void generate_wrap_statement(SourceGenerator& generator, ByteString const
|
|||
generate_wrap_statement(union_generator, ByteString::formatted("visited_union_value{}", recursion_depth), current_union_type, interface, "return"sv, recursion_depth + 1);
|
||||
|
||||
// End of current visit lambda.
|
||||
// The last lambda cannot have a trailing comma on the closing brace, unless the type is nullable, where an extra lambda will be generated for the Empty case.
|
||||
if (current_union_type_index != union_types.size() - 1 || type.is_nullable()) {
|
||||
// The last lambda cannot have a trailing comma on the closing brace, unless the type includes a nullable type, where an extra lambda will be generated for the Empty case.
|
||||
if (current_union_type_index != union_types.size() - 1 || union_type.includes_nullable_type()) {
|
||||
union_generator.append(R"~~~(
|
||||
},
|
||||
)~~~");
|
||||
|
|
@ -2194,7 +2203,7 @@ static void generate_wrap_statement(SourceGenerator& generator, ByteString const
|
|||
}
|
||||
}
|
||||
|
||||
if (type.is_nullable()) {
|
||||
if (union_type.includes_nullable_type()) {
|
||||
union_generator.append(R"~~~(
|
||||
[](Empty) -> JS::Value {
|
||||
return JS::js_null();
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ void WorkerHost::run(GC::Ref<Web::Page> page, Web::HTML::TransferDataEncoder mes
|
|||
Web::HTML::MessageEventInit event_init {};
|
||||
event_init.data = GC::Ref { vm.empty_string() };
|
||||
event_init.ports = { inside_port };
|
||||
event_init.source = inside_port;
|
||||
event_init.source = Web::HTML::NullableMessageEventSource { inside_port };
|
||||
|
||||
auto message_event = Web::HTML::MessageEvent::create(realm, Web::HTML::EventNames::connect, event_init);
|
||||
worker_global_scope->dispatch_event(message_event);
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ Harness status: OK
|
|||
|
||||
Found 5 tests
|
||||
|
||||
2 Pass
|
||||
3 Fail
|
||||
3 Pass
|
||||
2 Fail
|
||||
Pass currentTime can be used to seek a CSS transition
|
||||
Fail Skipping forwards through transition
|
||||
Pass Skipping backwards through transition
|
||||
Fail Setting currentTime to null on a CSS transition throws
|
||||
Pass Setting currentTime to null on a CSS transition throws
|
||||
Fail Transition reversing behavior respects currentTime and uses the transition's current position.
|
||||
|
|
@ -2,16 +2,16 @@ Harness status: OK
|
|||
|
||||
Found 13 tests
|
||||
|
||||
9 Pass
|
||||
4 Fail
|
||||
12 Pass
|
||||
1 Fail
|
||||
Pass Validate different value types that can be used to set start time
|
||||
Fail Setting the start time of an animation without an active timeline
|
||||
Fail Setting an unresolved start time an animation without an active timeline does not clear the current time
|
||||
Pass Setting an unresolved start time an animation without an active timeline does not clear the current time
|
||||
Pass Setting the start time clears the hold time
|
||||
Fail Setting an unresolved start time sets the hold time
|
||||
Pass Setting an unresolved start time sets the hold time
|
||||
Pass Setting the start time resolves a pending ready promise
|
||||
Pass Setting the start time resolves a pending pause task
|
||||
Fail Setting an unresolved start time on a play-pending animation makes it paused
|
||||
Pass Setting an unresolved start time on a play-pending animation makes it paused
|
||||
Pass Setting the start time updates the finished state
|
||||
Pass Setting the start time of a play-pending animation applies a pending playback rate
|
||||
Pass Setting the start time of a playing animation applies a pending playback rate
|
||||
|
|
|
|||
Loading…
Reference in a new issue