LibWeb: Implement the CEReactions extended attribute

This commit is contained in:
Luke Wilde 2023-03-28 18:10:26 +01:00 committed by Andreas Kling
parent 32e27bc7fa
commit e3c3cc9e19

View file

@ -1874,9 +1874,40 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@@overload_suffi
function_generator.set(".arguments", arguments_builder.string_view());
if (is_static_function == StaticFunction::No) {
function_generator.append(R"~~~(
// For [CEReactions]: https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
if (function.extended_attributes.contains("CEReactions")) {
// 1. Push a new element queue onto this object's relevant agent's custom element reactions stack.
function_generator.append(R"~~~(
auto& relevant_agent = HTML::relevant_agent(*impl);
auto* custom_data = verify_cast<Bindings::WebEngineCustomData>(relevant_agent.custom_data());
auto& reactions_stack = custom_data->custom_element_reactions_stack;
reactions_stack.element_queue_stack.append({});
)~~~");
}
if (!function.extended_attributes.contains("CEReactions")) {
function_generator.append(R"~~~(
[[maybe_unused]] auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->@function.cpp_name@(@.arguments@); }));
)~~~");
} else {
// 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
// 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
// 4. Invoke custom element reactions in queue.
// 5. If an exception exception was thrown by the original steps, rethrow exception.
// 6. If a value value was returned from the original steps, return value.
function_generator.append(R"~~~(
auto retval_or_exception = throw_dom_exception_if_needed(vm, [&] { return impl->@function.cpp_name@(@.arguments@); });
auto queue = reactions_stack.element_queue_stack.take_last();
Bindings::invoke_custom_element_reactions(queue);
if (retval_or_exception.is_error())
return retval_or_exception.release_error();
[[maybe_unused]] auto retval = retval_or_exception.release_value();
)~~~");
}
} else {
// Make sure first argument for static functions is the Realm.
if (arguments_builder.is_empty())
@ -2671,6 +2702,8 @@ static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm)
attribute_generator.set("attribute.reflect_name", attribute.name.to_snakecase());
}
// For [CEReactions]: https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
attribute_generator.append(R"~~~(
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
{
@ -2678,6 +2711,16 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
auto* impl = TRY(impl_from(vm));
)~~~");
if (attribute.extended_attributes.contains("CEReactions")) {
// 1. Push a new element queue onto this object's relevant agent's custom element reactions stack.
attribute_generator.append(R"~~~(
auto& relevant_agent = HTML::relevant_agent(*impl);
auto* custom_data = verify_cast<Bindings::WebEngineCustomData>(relevant_agent.custom_data());
auto& reactions_stack = custom_data->custom_element_reactions_stack;
reactions_stack.element_queue_stack.append({});
)~~~");
}
if (attribute.extended_attributes.contains("Reflect")) {
if (attribute.type->name() != "boolean") {
attribute_generator.append(R"~~~(
@ -2686,12 +2729,43 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
} else {
attribute_generator.append(R"~~~(
auto retval = impl->has_attribute(HTML::AttributeNames::@attribute.reflect_name@);
)~~~");
}
if (attribute.extended_attributes.contains("CEReactions")) {
// 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
// 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
// 4. Invoke custom element reactions in queue.
// 5. If an exception exception was thrown by the original steps, rethrow exception.
// 6. If a value value was returned from the original steps, return value.
attribute_generator.append(R"~~~(
auto queue = reactions_stack.element_queue_stack.take_last();
Bindings::invoke_custom_element_reactions(queue);
)~~~");
}
} else {
attribute_generator.append(R"~~~(
if (!attribute.extended_attributes.contains("CEReactions")) {
attribute_generator.append(R"~~~(
auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->@attribute.cpp_name@(); }));
)~~~");
} else {
// 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
// 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
// 4. Invoke custom element reactions in queue.
// 5. If an exception exception was thrown by the original steps, rethrow exception.
// 6. If a value value was returned from the original steps, return value.
attribute_generator.append(R"~~~(
auto retval_or_exception = throw_dom_exception_if_needed(vm, [&] { return impl->@attribute.cpp_name@(); });
auto queue = reactions_stack.element_queue_stack.take_last();
Bindings::invoke_custom_element_reactions(queue);
if (retval_or_exception.is_error())
return retval_or_exception.release_error();
auto retval = retval_or_exception.release_value();
)~~~");
}
}
generate_return_statement(generator, *attribute.type, interface);
@ -2701,6 +2775,8 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
)~~~");
if (!attribute.readonly) {
// For [CEReactions]: https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
attribute_generator.append(R"~~~(
JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
{
@ -2710,6 +2786,16 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
auto value = vm.argument(0);
)~~~");
if (attribute.extended_attributes.contains("CEReactions")) {
// 1. Push a new element queue onto this object's relevant agent's custom element reactions stack.
attribute_generator.append(R"~~~(
auto& relevant_agent = HTML::relevant_agent(*impl);
auto* custom_data = verify_cast<Bindings::WebEngineCustomData>(relevant_agent.custom_data());
auto& reactions_stack = custom_data->custom_element_reactions_stack;
reactions_stack.element_queue_stack.append({});
)~~~");
}
generate_to_cpp(generator, attribute, "value", "", "cpp_value", interface, attribute.extended_attributes.contains("LegacyNullToEmptyString"));
if (attribute.extended_attributes.contains("Reflect")) {
@ -2723,12 +2809,41 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
impl->remove_attribute(HTML::AttributeNames::@attribute.reflect_name@);
else
MUST(impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, DeprecatedString::empty()));
)~~~");
}
if (attribute.extended_attributes.contains("CEReactions")) {
// 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
// 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
// 4. Invoke custom element reactions in queue.
// 5. If an exception exception was thrown by the original steps, rethrow exception.
// 6. If a value value was returned from the original steps, return value.
attribute_generator.append(R"~~~(
auto queue = reactions_stack.element_queue_stack.take_last();
Bindings::invoke_custom_element_reactions(queue);
)~~~");
}
} else {
attribute_generator.append(R"~~~(
if (!attribute.extended_attributes.contains("CEReactions")) {
attribute_generator.append(R"~~~(
TRY(throw_dom_exception_if_needed(vm, [&] { return impl->set_@attribute.cpp_name@(cpp_value); }));
)~~~");
} else {
// 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
// 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
// 4. Invoke custom element reactions in queue.
// 5. If an exception exception was thrown by the original steps, rethrow exception.
// 6. If a value value was returned from the original steps, return value.
attribute_generator.append(R"~~~(
auto maybe_exception = throw_dom_exception_if_needed(vm, [&] { return impl->set_@attribute.cpp_name@(cpp_value); });
auto queue = reactions_stack.element_queue_stack.take_last();
Bindings::invoke_custom_element_reactions(queue);
if (maybe_exception.is_error())
return maybe_exception.release_error();
)~~~");
}
}
attribute_generator.append(R"~~~(
@ -3378,6 +3493,38 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu
)~~~");
bool has_ce_reactions = false;
for (auto const& function : interface.functions) {
if (function.extended_attributes.contains("CEReactions")) {
has_ce_reactions = true;
break;
}
}
if (!has_ce_reactions) {
for (auto const& attribute : interface.attributes) {
if (attribute.extended_attributes.contains("CEReactions")) {
has_ce_reactions = true;
break;
}
}
}
if (!has_ce_reactions && interface.indexed_property_setter.has_value() && interface.indexed_property_setter->extended_attributes.contains("CEReactions"))
has_ce_reactions = true;
if (!has_ce_reactions && interface.named_property_setter.has_value() && interface.named_property_setter->extended_attributes.contains("CEReactions"))
has_ce_reactions = true;
if (!has_ce_reactions && interface.named_property_deleter.has_value() && interface.named_property_deleter->extended_attributes.contains("CEReactions"))
has_ce_reactions = true;
if (has_ce_reactions) {
generator.append(R"~~~(
#include <LibWeb/Bindings/MainThreadVM.h>
)~~~");
}
for (auto& path : interface.required_imported_paths)
generate_include_for(generator, path);